From patchwork Tue Feb 12 02:00:08 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: David Gibson X-Patchwork-Id: 219721 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (Client did not present a certificate) by ozlabs.org (Postfix) with ESMTPS id 0E1FA2C02B8 for ; Tue, 12 Feb 2013 13:02:36 +1100 (EST) Received: from localhost ([::1]:53388 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1U55Cc-0002p4-3G for incoming@patchwork.ozlabs.org; Mon, 11 Feb 2013 21:02:34 -0500 Received: from eggs.gnu.org ([208.118.235.92]:33737) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1U55At-00019M-R2 for qemu-devel@nongnu.org; Mon, 11 Feb 2013 21:01:07 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1U55Ag-00060P-FQ for qemu-devel@nongnu.org; Mon, 11 Feb 2013 21:00:46 -0500 Received: from ozlabs.org ([203.10.76.45]:43643) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1U55Af-0005zT-SO; Mon, 11 Feb 2013 21:00:34 -0500 Received: by ozlabs.org (Postfix, from userid 1007) id 3A9F42C030B; Tue, 12 Feb 2013 13:00:16 +1100 (EST) From: David Gibson To: agraf@suse.de Date: Tue, 12 Feb 2013 13:00:08 +1100 Message-Id: <1360634411-5518-6-git-send-email-david@gibson.dropbear.id.au> X-Mailer: git-send-email 1.7.10.4 In-Reply-To: <1360634411-5518-1-git-send-email-david@gibson.dropbear.id.au> References: <1360634411-5518-1-git-send-email-david@gibson.dropbear.id.au> X-detected-operating-system: by eggs.gnu.org: GNU/Linux 3.x X-Received-From: 203.10.76.45 Cc: qemu-ppc@nongnu.org, qemu-devel@nongnu.org, David Gibson Subject: [Qemu-devel] [PATCH 5/8] target-ppc: Disentangle 64-bit version of get_segment() X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org 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. Signed-off-by: David Gibson --- target-ppc/cpu.h | 5 +-- target-ppc/mmu-hash64.c | 114 +++++++++++++++++++++++++++++++++++++++++++++-- target-ppc/mmu_helper.c | 108 +++++++++++++------------------------------- 3 files changed, 143 insertions(+), 84 deletions(-) diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h index da4bc17..cf12632 100644 --- a/target-ppc/cpu.h +++ b/target-ppc/cpu.h @@ -1152,10 +1152,9 @@ 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 find_pte64(CPUPPCState *env, mmu_ctx_t *ctx, int h, - int rw, int type, int target_page_bits); +int get_segment64(CPUPPCState *env, mmu_ctx_t *ctx, + target_ulong eaddr, int rw, int type); #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 465592a..1d6425c 100644 --- a/target-ppc/mmu-hash64.c +++ b/target-ppc/mmu-hash64.c @@ -43,7 +43,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; @@ -275,8 +275,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; @@ -348,3 +348,111 @@ 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 ds %d nx %d vsid " TARGET_FMT_lx "\n", + ctx->key, ds, 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 */ + if (eaddr != 0xEFFFFFFF) { + 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; + } + } +#if defined(DUMP_PAGE_TABLES) + if (qemu_log_enabled()) { + hwaddr curaddr; + uint32_t a0, a1, a2, a3; + + qemu_log("Page table: " TARGET_FMT_plx " len " TARGET_FMT_plx + "\n", sdr, mask + 0x80); + for (curaddr = sdr; curaddr < (sdr + mask + 0x80); + curaddr += 16) { + a0 = ldl_phys(curaddr); + a1 = ldl_phys(curaddr + 4); + a2 = ldl_phys(curaddr + 8); + a3 = ldl_phys(curaddr + 12); + if (a0 != 0 || a1 != 0 || a2 != 0 || a3 != 0) { + qemu_log(TARGET_FMT_plx ": %08x %08x %08x %08x\n", + curaddr, a0, a1, a2, a3); + } + } + } +#endif + } else { + LOG_MMU("No access allowed\n"); + ret = -3; + } + + return ret; +} diff --git a/target-ppc/mmu_helper.c b/target-ppc/mmu_helper.c index 48dc658..e9f8949 100644 --- a/target-ppc/mmu_helper.c +++ b/target-ppc/mmu_helper.c @@ -578,87 +578,35 @@ static inline int find_pte32(CPUPPCState *env, mmu_ctx_t *ctx, int h, 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_pte64(env, ctx, h, rw, type, target_page_bits); - } -#endif - - return find_pte32(env, ctx, h, rw, type, target_page_bits); -} - /* Perform segment based translation */ -static inline int get_segment(CPUPPCState *env, mmu_ctx_t *ctx, - target_ulong eaddr, int rw, int type) +static inline int get_segment32(CPUPPCState *env, mmu_ctx_t *ctx, + target_ulong eaddr, int rw, int type) { hwaddr hash; target_ulong vsid; int ds, pr, target_page_bits; int ret, ret2; + target_ulong sr, pgidx; pr = msr_pr; ctx->eaddr = eaddr; -#if defined(TARGET_PPC64) - if (env->mmu_model & POWERPC_MMU_64) { - 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)); - ds = 0; - ctx->nx = !!(slb->vsid & SLB_VSID_N); + sr = env->sr[eaddr >> 28]; + ctx->key = (((sr & 0x20000000) && (pr != 0)) || + ((sr & 0x40000000) && (pr == 0))) ? 1 : 0; + ds = sr & 0x80000000 ? 1 : 0; + ctx->nx = sr & 0x10000000 ? 1 : 0; + vsid = sr & 0x00FFFFFF; + target_page_bits = TARGET_PAGE_BITS; + LOG_MMU("Check segment v=" TARGET_FMT_lx " %d " TARGET_FMT_lx " nip=" + TARGET_FMT_lx " lr=" TARGET_FMT_lx + " ir=%d dr=%d pr=%d %d t=%d\n", + eaddr, (int)(eaddr >> 28), sr, env->nip, env->lr, (int)msr_ir, + (int)msr_dr, pr != 0 ? 1 : 0, rw, type); + pgidx = (eaddr & ~SEGMENT_MASK_256M) >> target_page_bits; + hash = vsid ^ pgidx; + ctx->ptem = (vsid << 7) | (pgidx >> 10); - 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)); - } else -#endif /* defined(TARGET_PPC64) */ - { - target_ulong sr, pgidx; - - sr = env->sr[eaddr >> 28]; - ctx->key = (((sr & 0x20000000) && (pr != 0)) || - ((sr & 0x40000000) && (pr == 0))) ? 1 : 0; - ds = sr & 0x80000000 ? 1 : 0; - ctx->nx = sr & 0x10000000 ? 1 : 0; - vsid = sr & 0x00FFFFFF; - target_page_bits = TARGET_PAGE_BITS; - LOG_MMU("Check segment v=" TARGET_FMT_lx " %d " TARGET_FMT_lx " nip=" - TARGET_FMT_lx " lr=" TARGET_FMT_lx - " ir=%d dr=%d pr=%d %d t=%d\n", - eaddr, (int)(eaddr >> 28), sr, env->nip, env->lr, (int)msr_ir, - (int)msr_dr, pr != 0 ? 1 : 0, rw, type); - pgidx = (eaddr & ~SEGMENT_MASK_256M) >> target_page_bits; - hash = vsid ^ pgidx; - ctx->ptem = (vsid << 7) | (pgidx >> 10); - } LOG_MMU("pte segment: key=%d ds %d nx %d vsid " TARGET_FMT_lx "\n", ctx->key, ds, ctx->nx, vsid); ret = -1; @@ -685,7 +633,7 @@ static inline int get_segment(CPUPPCState *env, mmu_ctx_t *ctx, env->htab_base, env->htab_mask, vsid, ctx->ptem, ctx->hash[0]); /* Primary table lookup */ - ret = find_pte(env, ctx, 0, rw, type, target_page_bits); + ret = find_pte32(env, ctx, 0, rw, type, target_page_bits); if (ret < 0) { /* Secondary table lookup */ if (eaddr != 0xEFFFFFFF) { @@ -694,8 +642,8 @@ static inline int get_segment(CPUPPCState *env, mmu_ctx_t *ctx, " hash=" TARGET_FMT_plx "\n", env->htab_base, env->htab_mask, vsid, ctx->ptem, ctx->hash[1]); } - ret2 = find_pte(env, ctx, 1, rw, type, - target_page_bits); + ret2 = find_pte32(env, ctx, 1, rw, type, + target_page_bits); if (ret2 != -1) { ret = ret2; } @@ -1494,16 +1442,20 @@ static int get_physical_address(CPUPPCState *env, mmu_ctx_t *ctx, if (env->nb_BATs != 0) { ret = get_bat(env, ctx, eaddr, rw, access_type); } + if (ret < 0) { + /* We didn't match any BAT entry or don't have BATs */ + ret = get_segment32(env, ctx, eaddr, rw, access_type); + } + break; + #if defined(TARGET_PPC64) case POWERPC_MMU_64B: case POWERPC_MMU_2_06: case POWERPC_MMU_2_06d: -#endif - if (ret < 0) { - /* We didn't match any BAT entry or don't have BATs */ - ret = get_segment(env, ctx, eaddr, rw, access_type); - } + ret = get_segment64(env, ctx, eaddr, rw, access_type); break; +#endif + case POWERPC_MMU_SOFT_4xx: case POWERPC_MMU_SOFT_4xx_Z: ret = mmu40x_get_physical_address(env, ctx, eaddr,