From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mailman by lists.gnu.org with tmda-scanned (Exim 4.43) id 1Lg3UP-0005Bb-3R for qemu-devel@nongnu.org; Sat, 07 Mar 2009 15:51:21 -0500 Received: from exim by lists.gnu.org with spam-scanned (Exim 4.43) id 1Lg3UO-0005BP-Dc for qemu-devel@nongnu.org; Sat, 07 Mar 2009 15:51:20 -0500 Received: from [199.232.76.173] (port=46642 helo=monty-python.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1Lg3UO-0005BM-4W for qemu-devel@nongnu.org; Sat, 07 Mar 2009 15:51:20 -0500 Received: from savannah.gnu.org ([199.232.41.3]:59944 helo=sv.gnu.org) by monty-python.gnu.org with esmtps (TLS-1.0:RSA_AES_256_CBC_SHA1:32) (Exim 4.60) (envelope-from ) id 1Lg3UN-0007bD-MG for qemu-devel@nongnu.org; Sat, 07 Mar 2009 15:51:19 -0500 Received: from cvs.savannah.gnu.org ([199.232.41.69]) by sv.gnu.org with esmtp (Exim 4.69) (envelope-from ) id 1Lg3UN-0002zU-3q for qemu-devel@nongnu.org; Sat, 07 Mar 2009 20:51:19 +0000 Received: from blueswir1 by cvs.savannah.gnu.org with local (Exim 4.69) (envelope-from ) id 1Lg3UM-0002zQ-R0 for qemu-devel@nongnu.org; Sat, 07 Mar 2009 20:51:19 +0000 MIME-Version: 1.0 Errors-To: blueswir1 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit From: Blue Swirl Message-Id: Date: Sat, 07 Mar 2009 20:51:18 +0000 Subject: [Qemu-devel] [6748] Implement large pages Reply-To: qemu-devel@nongnu.org List-Id: qemu-devel.nongnu.org List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , To: qemu-devel@nongnu.org Revision: 6748 http://svn.sv.gnu.org/viewvc/?view=rev&root=qemu&revision=6748 Author: blueswir1 Date: 2009-03-07 20:51:18 +0000 (Sat, 07 Mar 2009) Log Message: ----------- Implement large pages The current SLB/PTE code does not support large pages, which are required by Linux, as it boots up with the kernel regions up as large. This patch implements large page support, so we can run Linux. Signed-off-by: Alexander Graf Modified Paths: -------------- trunk/target-ppc/cpu.h trunk/target-ppc/helper.c Modified: trunk/target-ppc/cpu.h =================================================================== --- trunk/target-ppc/cpu.h 2009-03-07 20:50:01 UTC (rev 6747) +++ trunk/target-ppc/cpu.h 2009-03-07 20:51:18 UTC (rev 6748) @@ -677,6 +677,7 @@ typedef struct mmu_ctx_t mmu_ctx_t; struct mmu_ctx_t { target_phys_addr_t raddr; /* Real address */ + target_phys_addr_t eaddr; /* Effective address */ int prot; /* Protection bits */ target_phys_addr_t pg_addr[2]; /* PTE tables base addresses */ target_ulong ptem; /* Virtual segment ID | API */ Modified: trunk/target-ppc/helper.c =================================================================== --- trunk/target-ppc/helper.c 2009-03-07 20:50:01 UTC (rev 6747) +++ trunk/target-ppc/helper.c 2009-03-07 20:51:18 UTC (rev 6748) @@ -582,7 +582,8 @@ /* PTE table lookup */ static always_inline int _find_pte (mmu_ctx_t *ctx, int is_64b, int h, - int rw, int type) + int rw, int type, + int target_page_bits) { target_ulong base, pte0, pte1; int i, good = -1; @@ -594,7 +595,14 @@ #if defined(TARGET_PPC64) if (is_64b) { pte0 = ldq_phys(base + (i * 16)); - pte1 = ldq_phys(base + (i * 16) + 8); + pte1 = ldq_phys(base + (i * 16) + 8); + + /* 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) + pte1 |= (ctx->eaddr & (( 1 << target_page_bits ) - 1)) + & TARGET_PAGE_MASK; + r = pte64_check(ctx, pte0, pte1, h, rw, type); LOG_MMU("Load pte from " ADDRX " => " ADDRX " " ADDRX " %d %d %d " ADDRX "\n", @@ -658,27 +666,30 @@ return ret; } -static always_inline int find_pte32 (mmu_ctx_t *ctx, int h, int rw, int type) +static always_inline int find_pte32 (mmu_ctx_t *ctx, int h, int rw, + int type, int target_page_bits) { - return _find_pte(ctx, 0, h, rw, type); + return _find_pte(ctx, 0, h, rw, type, target_page_bits); } #if defined(TARGET_PPC64) -static always_inline int find_pte64 (mmu_ctx_t *ctx, int h, int rw, int type) +static always_inline int find_pte64 (mmu_ctx_t *ctx, int h, int rw, + int type, int target_page_bits) { - return _find_pte(ctx, 1, h, rw, type); + return _find_pte(ctx, 1, h, rw, type, target_page_bits); } #endif static always_inline int find_pte (CPUState *env, mmu_ctx_t *ctx, - int h, int rw, int type) + int h, int rw, int type, + int target_page_bits) { #if defined(TARGET_PPC64) if (env->mmu_model & POWERPC_MMU_64) - return find_pte64(ctx, h, rw, type); + return find_pte64(ctx, h, rw, type, target_page_bits); #endif - return find_pte32(ctx, h, rw, type); + return find_pte32(ctx, h, rw, type, target_page_bits); } #if defined(TARGET_PPC64) @@ -694,7 +705,8 @@ static always_inline int slb_lookup (CPUPPCState *env, target_ulong eaddr, target_ulong *vsid, - target_ulong *page_mask, int *attr) + target_ulong *page_mask, int *attr, + int *target_page_bits) { target_phys_addr_t sr_base; target_ulong mask; @@ -714,19 +726,16 @@ PRIx32 "\n", __func__, n, sr_base, tmp64, tmp); if (slb_is_valid(tmp64)) { /* SLB entry is valid */ - switch (tmp64 & 0x0000000006000000ULL) { - case 0x0000000000000000ULL: - /* 256 MB segment */ + if (tmp & 0x8) { + /* 1 TB Segment */ + mask = 0xFFFF000000000000ULL; + if (target_page_bits) + *target_page_bits = 24; // XXX 16M pages? + } else { + /* 256MB Segment */ mask = 0xFFFFFFFFF0000000ULL; - break; - case 0x0000000002000000ULL: - /* 1 TB segment */ - mask = 0xFFFF000000000000ULL; - break; - case 0x0000000004000000ULL: - case 0x0000000006000000ULL: - /* Reserved => segment is invalid */ - continue; + if (target_page_bits) + *target_page_bits = TARGET_PAGE_BITS; } if ((eaddr & mask) == (tmp64 & mask)) { /* SLB match */ @@ -777,7 +786,7 @@ int attr; int n; - n = slb_lookup(env, T0, &vsid, &page_mask, &attr); + n = slb_lookup(env, T0, &vsid, &page_mask, &attr, NULL); if (n >= 0) { sr_base = env->spr[SPR_ASR]; sr_base += 12 * n; @@ -871,20 +880,22 @@ #if defined(TARGET_PPC64) int attr; #endif - int ds, vsid_sh, sdr_sh, pr; + int ds, vsid_sh, sdr_sh, pr, target_page_bits; int ret, ret2; pr = msr_pr; #if defined(TARGET_PPC64) if (env->mmu_model & POWERPC_MMU_64) { LOG_MMU("Check SLBs\n"); - ret = slb_lookup(env, eaddr, &vsid, &page_mask, &attr); + ret = slb_lookup(env, eaddr, &vsid, &page_mask, &attr, + &target_page_bits); if (ret < 0) return ret; ctx->key = ((attr & 0x40) && (pr != 0)) || ((attr & 0x80) && (pr == 0)) ? 1 : 0; ds = 0; - ctx->nx = attr & 0x20 ? 1 : 0; + ctx->nx = attr & 0x10 ? 1 : 0; + ctx->eaddr = eaddr; vsid_mask = 0x00003FFFFFFFFF80ULL; vsid_sh = 7; sdr_sh = 18; @@ -903,6 +914,7 @@ vsid_sh = 6; sdr_sh = 16; sdr_mask = 0xFFC0; + target_page_bits = TARGET_PAGE_BITS; LOG_MMU("Check segment v=" ADDRX " %d " ADDRX " nip=" ADDRX " lr=" ADDRX " ir=%d dr=%d pr=%d %d t=%d\n", eaddr, (int)(eaddr >> 28), sr, env->nip, @@ -918,7 +930,7 @@ /* Page address translation */ /* Primary table address */ sdr = env->sdr1; - pgidx = (eaddr & page_mask) >> TARGET_PAGE_BITS; + pgidx = (eaddr & page_mask) >> target_page_bits; #if defined(TARGET_PPC64) if (env->mmu_model & POWERPC_MMU_64) { htab_mask = 0x0FFFFFFF >> (28 - (sdr & 0x1F)); @@ -944,7 +956,12 @@ #if defined(TARGET_PPC64) if (env->mmu_model & POWERPC_MMU_64) { /* Only 5 bits of the page index are used in the AVPN */ - ctx->ptem = (vsid << 12) | ((pgidx >> 4) & 0x0F80); + if (target_page_bits > 23) { + ctx->ptem = (vsid << 12) | + ((pgidx << (target_page_bits - 16)) & 0xF80); + } else { + ctx->ptem = (vsid << 12) | ((pgidx >> 4) & 0x0F80); + } } else #endif { @@ -962,7 +979,7 @@ " pg_addr=" PADDRX "\n", sdr, vsid, pgidx, hash, ctx->pg_addr[0]); /* Primary table lookup */ - ret = find_pte(env, ctx, 0, rw, type); + ret = find_pte(env, ctx, 0, rw, type, target_page_bits); if (ret < 0) { /* Secondary table lookup */ if (eaddr != 0xEFFFFFFF) @@ -970,7 +987,8 @@ "api=" ADDRX " hash=" PADDRX " pg_addr=" PADDRX "\n", sdr, vsid, pgidx, hash, ctx->pg_addr[1]); - ret2 = find_pte(env, ctx, 1, rw, type); + ret2 = find_pte(env, ctx, 1, rw, type, + target_page_bits); if (ret2 != -1) ret = ret2; }