From patchwork Tue Jul 5 02:33:48 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: David Gibson X-Patchwork-Id: 9213471 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id CC26260572 for ; Tue, 5 Jul 2016 02:36:14 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id BAE9C28818 for ; Tue, 5 Jul 2016 02:36:14 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id ACF9E2881F; Tue, 5 Jul 2016 02:36:14 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-6.8 required=2.0 tests=BAYES_00,DKIM_SIGNED, RCVD_IN_DNSWL_HI,T_DKIM_INVALID autolearn=ham version=3.3.1 Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (No client certificate requested) by mail.wl.linuxfoundation.org (Postfix) with ESMTPS id E914A28818 for ; Tue, 5 Jul 2016 02:36:13 +0000 (UTC) Received: from localhost ([::1]:51563 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1bKGDd-0006pF-4B for patchwork-qemu-devel@patchwork.kernel.org; Mon, 04 Jul 2016 22:36:13 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:35210) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1bKG9g-0003bJ-Hn for qemu-devel@nongnu.org; Mon, 04 Jul 2016 22:32:09 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1bKG9f-0000pv-B2 for qemu-devel@nongnu.org; Mon, 04 Jul 2016 22:32:08 -0400 Received: from ozlabs.org ([2401:3900:2:1::2]:48601) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1bKG9e-0000pM-Ng; Mon, 04 Jul 2016 22:32:07 -0400 Received: by ozlabs.org (Postfix, from userid 1007) id 3rk7FG3Yhkz9sXy; Tue, 5 Jul 2016 12:32:02 +1000 (AEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=gibson.dropbear.id.au; s=201602; t=1467685922; bh=y8aBUTafKVrM76Bel7m3ywpXS5vdGDCKNt4MjW349Kg=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=FmDLHfLpJ7TyYE81zY4xTBL1rpV7pYndkzDp3tgAzvHbJeZZ032qZx3BauPG6MIjT 1pAQotWxxGfCu+bQ+kyoGFbaGimEzwp2A3xZj2QppolMRpDuvQONGfusy2FIvXybU6 8LvtqRPTHsdjmidwXjeHybovrSZhz7J0IQOT87PA= From: David Gibson To: benh@kernel.crashing.org Date: Tue, 5 Jul 2016 12:33:48 +1000 Message-Id: <1467686030-2018-2-git-send-email-david@gibson.dropbear.id.au> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1467686030-2018-1-git-send-email-david@gibson.dropbear.id.au> References: <1467686030-2018-1-git-send-email-david@gibson.dropbear.id.au> X-detected-operating-system: by eggs.gnu.org: Genre and OS details not recognized. X-Received-From: 2401:3900:2:1::2 Subject: [Qemu-devel] [PATCH 1/3] target-ppc: Correct page size decoding in ppc_hash64_pteg_search() X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: David Gibson , qemu-ppc@nongnu.org, agraf@suse.de, qemu-devel@nongnu.org Errors-To: qemu-devel-bounces+patchwork-qemu-devel=patchwork.kernel.org@nongnu.org Sender: "Qemu-devel" X-Virus-Scanned: ClamAV using ClamSMTP The architecture specifies that when searching a PTEG for PTEs, entries with a page size encoding that's not valid for the current segment should be ignored, continuing the search. The current implementation does this with ppc_hash64_pte_size_decode() which is a very incomplete implementation of this check. We already have code to do a full and correct page size decode in hpte_page_shift(). This patch moves hpte_page_shift() so it can be used in ppc_hash64_pteg_search() and adjusts the latter's parameters to include a full SLBE instead of just a segment page shift. Signed-off-by: David Gibson --- target-ppc/mmu-hash64.c | 99 ++++++++++++++++++++----------------------------- 1 file changed, 41 insertions(+), 58 deletions(-) diff --git a/target-ppc/mmu-hash64.c b/target-ppc/mmu-hash64.c index 3b1357a..cbc5c0a 100644 --- a/target-ppc/mmu-hash64.c +++ b/target-ppc/mmu-hash64.c @@ -450,30 +450,45 @@ void ppc_hash64_stop_access(PowerPCCPU *cpu, uint64_t token) } } -/* Returns the effective page shift or 0. MPSS isn't supported yet so - * this will always be the slb_pshift or 0 - */ -static uint32_t ppc_hash64_pte_size_decode(uint64_t pte1, uint32_t slb_pshift) +static unsigned hpte_page_shift(const struct ppc_one_seg_page_size *sps, + uint64_t pte0, uint64_t pte1) { - switch (slb_pshift) { - case 12: + int i; + + if (!(pte0 & HPTE64_V_LARGE)) { + if (sps->page_shift != 12) { + /* 4kiB page in a non 4kiB segment */ + return 0; + } + /* Normal 4kiB page */ return 12; - case 16: - if ((pte1 & 0xf000) == 0x1000) { - return 16; + } + + for (i = 0; i < PPC_PAGE_SIZES_MAX_SZ; i++) { + const struct ppc_one_page_size *ps = &sps->enc[i]; + uint64_t mask; + + if (!ps->page_shift) { + break; } - return 0; - case 24: - if ((pte1 & 0xff000) == 0) { - return 24; + + if (ps->page_shift == 12) { + /* L bit is set so this can't be a 4kiB page */ + continue; + } + + mask = ((1ULL << ps->page_shift) - 1) & HPTE64_R_RPN; + + if ((pte1 & mask) == (ps->pte_enc << HPTE64_R_RPN_SHIFT)) { + return ps->page_shift; } - return 0; } - return 0; + + return 0; /* Bad page size encoding */ } static hwaddr ppc_hash64_pteg_search(PowerPCCPU *cpu, hwaddr hash, - uint32_t slb_pshift, bool secondary, + ppc_slb_t *slb, bool secondary, target_ulong ptem, ppc_hash_pte64_t *pte) { CPUPPCState *env = &cpu->env; @@ -494,7 +509,14 @@ static hwaddr ppc_hash64_pteg_search(PowerPCCPU *cpu, hwaddr hash, if ((pte0 & HPTE64_V_VALID) && (secondary == !!(pte0 & HPTE64_V_SECONDARY)) && HPTE64_V_COMPARE(pte0, ptem)) { - uint32_t pshift = ppc_hash64_pte_size_decode(pte1, slb_pshift); + unsigned pshift = hpte_page_shift(slb->sps, pte0, pte1); + /* + * If there is no match, ignore the PTE, it could simply + * be for a different segment size encoding and the + * architecture specifies we should not match. Linux will + * potentially leave behind PTEs for the wrong base page + * size when demoting segments. + */ if (pshift == 0) { continue; } @@ -554,8 +576,7 @@ static hwaddr ppc_hash64_htab_lookup(PowerPCCPU *cpu, " vsid=" TARGET_FMT_lx " ptem=" TARGET_FMT_lx " hash=" TARGET_FMT_plx "\n", env->htab_base, env->htab_mask, vsid, ptem, hash); - pte_offset = ppc_hash64_pteg_search(cpu, hash, slb->sps->page_shift, - 0, ptem, pte); + pte_offset = ppc_hash64_pteg_search(cpu, hash, slb, 0, ptem, pte); if (pte_offset == -1) { /* Secondary PTEG lookup */ @@ -565,50 +586,12 @@ static hwaddr ppc_hash64_htab_lookup(PowerPCCPU *cpu, " hash=" TARGET_FMT_plx "\n", env->htab_base, env->htab_mask, vsid, ptem, ~hash); - pte_offset = ppc_hash64_pteg_search(cpu, ~hash, slb->sps->page_shift, 1, - ptem, pte); + pte_offset = ppc_hash64_pteg_search(cpu, ~hash, slb, 1, ptem, pte); } return pte_offset; } -static unsigned hpte_page_shift(const struct ppc_one_seg_page_size *sps, - uint64_t pte0, uint64_t pte1) -{ - int i; - - if (!(pte0 & HPTE64_V_LARGE)) { - if (sps->page_shift != 12) { - /* 4kiB page in a non 4kiB segment */ - return 0; - } - /* Normal 4kiB page */ - return 12; - } - - for (i = 0; i < PPC_PAGE_SIZES_MAX_SZ; i++) { - const struct ppc_one_page_size *ps = &sps->enc[i]; - uint64_t mask; - - if (!ps->page_shift) { - break; - } - - if (ps->page_shift == 12) { - /* L bit is set so this can't be a 4kiB page */ - continue; - } - - mask = ((1ULL << ps->page_shift) - 1) & HPTE64_R_RPN; - - if ((pte1 & mask) == (ps->pte_enc << HPTE64_R_RPN_SHIFT)) { - return ps->page_shift; - } - } - - return 0; /* Bad page size encoding */ -} - unsigned ppc_hash64_hpte_page_shift_noslb(PowerPCCPU *cpu, uint64_t pte0, uint64_t pte1, unsigned *seg_page_shift)