From nobody Mon Feb 9 04:44:16 2026 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zohomail.com; spf=pass (zoho.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail(p=none dis=none) header.from=redhat.com ARC-Seal: i=1; a=rsa-sha256; t=1569418398; cv=none; d=zoho.com; s=zohoarc; b=emh0u7Lyy7PU5JwXZMEY1NOK3+cYQMScO1vfSBS/RcM7MrEpMHc3IDfvG8smpiUElughMWSx2F8/mcLkJU6ezjm1HQn2P3nFmZ8lTXyWJdEfgHC5GidXw7figFp2MN7hWIx827l1sBuEyJNFETbCtCcC35vEq4YmBrd7QFFVZns= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zoho.com; s=zohoarc; t=1569418398; h=Content-Transfer-Encoding:Cc:Date:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:To:ARC-Authentication-Results; bh=Mf213FsVGzaH6kN4cDOvxDzmGZxsrtQrTJ68DST/Kr0=; b=gqDtX8lmXKTySx9cyPXy/ugxnyGA9TmdVEGlATRsO7VdEta5aNkbFaZ3a94A5483VNe7teH5ChHExaKzuKh/0AlabqObc4i9ahKYLpimx1hMT8Q4HTl3jZ4n3+hPm2hZYmUrxTQiXANlgaxbeJny5OiC6c+bGsqaTTmzuSvqsw0= ARC-Authentication-Results: i=1; mx.zoho.com; spf=pass (zoho.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail header.from= (p=none dis=none) header.from= Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1569418398155630.7451042240016; Wed, 25 Sep 2019 06:33:18 -0700 (PDT) Received: from localhost ([::1]:50834 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1iD7Pv-00064y-UN for importer@patchew.org; Wed, 25 Sep 2019 09:33:15 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:58869) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1iD6n4-0006gJ-0F for qemu-devel@nongnu.org; Wed, 25 Sep 2019 08:53:07 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1iD6n2-0004CO-G9 for qemu-devel@nongnu.org; Wed, 25 Sep 2019 08:53:05 -0400 Received: from mx1.redhat.com ([209.132.183.28]:57816) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1iD6n2-0004C5-7x; Wed, 25 Sep 2019 08:53:04 -0400 Received: from smtp.corp.redhat.com (int-mx01.intmail.prod.int.phx2.redhat.com [10.5.11.11]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 5533E31752A4; Wed, 25 Sep 2019 12:53:03 +0000 (UTC) Received: from t460s.redhat.com (ovpn-117-14.ams2.redhat.com [10.36.117.14]) by smtp.corp.redhat.com (Postfix) with ESMTP id 85190600C8; Wed, 25 Sep 2019 12:53:01 +0000 (UTC) From: David Hildenbrand To: qemu-devel@nongnu.org Subject: [PATCH v2 7/7] s390x/mmu: Convert to non-recursive page table walk Date: Wed, 25 Sep 2019 14:52:36 +0200 Message-Id: <20190925125236.4043-8-david@redhat.com> In-Reply-To: <20190925125236.4043-1-david@redhat.com> References: <20190925125236.4043-1-david@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.79 on 10.5.11.11 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.49]); Wed, 25 Sep 2019 12:53:03 +0000 (UTC) Content-Transfer-Encoding: quoted-printable X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 209.132.183.28 X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Thomas Huth , Janosch Frank , David Hildenbrand , Cornelia Huck , Halil Pasic , Christian Borntraeger , qemu-s390x@nongnu.org, Richard Henderson Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" Content-Type: text/plain; charset="utf-8" A non-recursive implementation allows to make better use of the branch predictor, avoids function calls, and makes the implementation of new features only for a subset of region table levels easier. We can now directly compare our implementation to the KVM gaccess implementation in arch/s390/kvm/gaccess.c:guest_translate(). Signed-off-by: David Hildenbrand --- target/s390x/mmu_helper.c | 212 ++++++++++++++++++++------------------ 1 file changed, 112 insertions(+), 100 deletions(-) diff --git a/target/s390x/mmu_helper.c b/target/s390x/mmu_helper.c index 9243f04312..3ef40a37a7 100644 --- a/target/s390x/mmu_helper.c +++ b/target/s390x/mmu_helper.c @@ -111,107 +111,16 @@ static inline int read_table_entry(hwaddr gaddr, uin= t64_t *entry) return 0; } =20 -/* Decode page table entry (normal 4KB page) */ -static int mmu_translate_pte(CPUS390XState *env, target_ulong vaddr, - uint64_t asc, uint64_t pt_entry, - target_ulong *raddr, int *flags, int rw, bool= exc) -{ - if (pt_entry & PAGE_ENTRY_I) { - return PGM_PAGE_TRANS; - } - if (pt_entry & PAGE_ENTRY_0) { - return PGM_TRANS_SPEC; - } - if (pt_entry & PAGE_ENTRY_P) { - *flags &=3D ~PAGE_WRITE; - } - - *raddr =3D pt_entry & TARGET_PAGE_MASK; - return 0; -} - -/* Decode segment table entry */ -static int mmu_translate_segment(CPUS390XState *env, target_ulong vaddr, - uint64_t asc, uint64_t st_entry, - target_ulong *raddr, int *flags, int rw, - bool exc) -{ - uint64_t origin, offs, pt_entry; - - if (st_entry & SEGMENT_ENTRY_P) { - *flags &=3D ~PAGE_WRITE; - } - - if ((st_entry & SEGMENT_ENTRY_FC) && (env->cregs[0] & CR0_EDAT)) { - /* Decode EDAT1 segment frame absolute address (1MB page) */ - *raddr =3D (st_entry & SEGMENT_ENTRY_SFAA) | - (vaddr & ~SEGMENT_ENTRY_SFAA); - return 0; - } - - /* Look up 4KB page entry */ - origin =3D st_entry & SEGMENT_ENTRY_ORIGIN; - offs =3D VADDR_PAGE_TX(vaddr) * 8; - if (read_table_entry(origin + offs, &pt_entry)) { - return PGM_ADDRESSING; - } - return mmu_translate_pte(env, vaddr, asc, pt_entry, raddr, flags, rw, = exc); -} - -/* Decode region table entries */ -static int mmu_translate_region(CPUS390XState *env, target_ulong vaddr, - uint64_t asc, uint64_t entry, int level, - target_ulong *raddr, int *flags, int rw, - bool exc) -{ - uint64_t origin, offs, new_entry; - const int pchks[4] =3D { - PGM_SEGMENT_TRANS, PGM_REG_THIRD_TRANS, - PGM_REG_SEC_TRANS, PGM_REG_FIRST_TRANS - }; - - origin =3D entry & REGION_ENTRY_ORIGIN; - offs =3D (vaddr >> (17 + 11 * level / 4)) & 0x3ff8; - - if (read_table_entry(origin + offs, &new_entry)) { - return PGM_ADDRESSING; - } - - if (new_entry & REGION_ENTRY_I) { - return pchks[level / 4]; - } - - if ((new_entry & REGION_ENTRY_TT) !=3D level) { - return PGM_TRANS_SPEC; - } - - if (level =3D=3D ASCE_TYPE_SEGMENT) { - return mmu_translate_segment(env, vaddr, asc, new_entry, raddr, fl= ags, - rw, exc); - } - - /* Check region table offset and length */ - offs =3D (vaddr >> (28 + 11 * (level - 4) / 4)) & 3; - if (offs < ((new_entry & REGION_ENTRY_TF) >> 6) - || offs > (new_entry & REGION_ENTRY_TL)) { - return pchks[level / 4 - 1]; - } - - if ((env->cregs[0] & CR0_EDAT) && (new_entry & REGION_ENTRY_P)) { - *flags &=3D ~PAGE_WRITE; - } - - /* yet another region */ - return mmu_translate_region(env, vaddr, asc, new_entry, level - 4, - raddr, flags, rw, exc); -} - static int mmu_translate_asce(CPUS390XState *env, target_ulong vaddr, uint64_t asc, uint64_t asce, target_ulong *r= addr, int *flags, int rw, bool exc) { + const bool edat1 =3D (env->cregs[0] & CR0_EDAT) && + s390_has_feat(S390_FEAT_EDAT); const int asce_tl =3D asce & ASCE_TABLE_LENGTH; - int level; + const int asce_p =3D asce & ASCE_PRIVATE_SPACE; + hwaddr gaddr =3D asce & ASCE_ORIGIN; + uint64_t entry; =20 if (asce & ASCE_REAL_SPACE) { /* direct mapping */ @@ -219,12 +128,12 @@ static int mmu_translate_asce(CPUS390XState *env, tar= get_ulong vaddr, return 0; } =20 - level =3D asce & ASCE_TYPE_MASK; - switch (level) { + switch (asce & ASCE_TYPE_MASK) { case ASCE_TYPE_REGION1: if (VADDR_REGION1_TL(vaddr) > asce_tl) { return PGM_REG_FIRST_TRANS; } + gaddr +=3D VADDR_REGION1_TX(vaddr) * 8; break; case ASCE_TYPE_REGION2: if (VADDR_REGION1_TX(vaddr)) { @@ -233,6 +142,7 @@ static int mmu_translate_asce(CPUS390XState *env, targe= t_ulong vaddr, if (VADDR_REGION2_TL(vaddr) > asce_tl) { return PGM_REG_SEC_TRANS; } + gaddr +=3D VADDR_REGION2_TX(vaddr) * 8; break; case ASCE_TYPE_REGION3: if (VADDR_REGION1_TX(vaddr) || VADDR_REGION2_TX(vaddr)) { @@ -241,6 +151,7 @@ static int mmu_translate_asce(CPUS390XState *env, targe= t_ulong vaddr, if (VADDR_REGION3_TL(vaddr) > asce_tl) { return PGM_REG_THIRD_TRANS; } + gaddr +=3D VADDR_REGION3_TX(vaddr) * 8; break; case ASCE_TYPE_SEGMENT: if (VADDR_REGION1_TX(vaddr) || VADDR_REGION2_TX(vaddr) || @@ -250,11 +161,112 @@ static int mmu_translate_asce(CPUS390XState *env, ta= rget_ulong vaddr, if (VADDR_SEGMENT_TL(vaddr) > asce_tl) { return PGM_SEGMENT_TRANS; } + gaddr +=3D VADDR_SEGMENT_TX(vaddr) * 8; + break; + default: + g_assert_not_reached(); + } + + switch (asce & ASCE_TYPE_MASK) { + case ASCE_TYPE_REGION1: + if (read_table_entry(gaddr, &entry)) { + return PGM_ADDRESSING; + } + if (entry & REGION_ENTRY_I) { + return PGM_REG_FIRST_TRANS; + } + if ((entry & REGION_ENTRY_TT) !=3D REGION_ENTRY_TT_REGION1) { + return PGM_TRANS_SPEC; + } + if (VADDR_REGION2_TL(vaddr) < (entry & REGION_ENTRY_TF) >> 6 || + VADDR_REGION2_TL(vaddr) > (entry & REGION_ENTRY_TL)) { + return PGM_REG_SEC_TRANS; + } + if (edat1 && (entry & REGION_ENTRY_P)) { + *flags &=3D ~PAGE_WRITE; + } + gaddr =3D (entry & REGION_ENTRY_ORIGIN) + VADDR_REGION2_TX(vaddr) = * 8; + /* fall through */ + case ASCE_TYPE_REGION2: + if (read_table_entry(gaddr, &entry)) { + return PGM_ADDRESSING; + } + if (entry & REGION_ENTRY_I) { + return PGM_REG_SEC_TRANS; + } + if ((entry & REGION_ENTRY_TT) !=3D REGION_ENTRY_TT_REGION2) { + return PGM_TRANS_SPEC; + } + if (VADDR_REGION3_TL(vaddr) < (entry & REGION_ENTRY_TF) >> 6 || + VADDR_REGION3_TL(vaddr) > (entry & REGION_ENTRY_TL)) { + return PGM_REG_THIRD_TRANS; + } + if (edat1 && (entry & REGION_ENTRY_P)) { + *flags &=3D ~PAGE_WRITE; + } + gaddr =3D (entry & REGION_ENTRY_ORIGIN) + VADDR_REGION3_TX(vaddr) = * 8; + /* fall through */ + case ASCE_TYPE_REGION3: + if (read_table_entry(gaddr, &entry)) { + return PGM_ADDRESSING; + } + if (entry & REGION_ENTRY_I) { + return PGM_REG_THIRD_TRANS; + } + if ((entry & REGION_ENTRY_TT) !=3D REGION_ENTRY_TT_REGION3) { + return PGM_TRANS_SPEC; + } + if (edat1 && (entry & REGION_ENTRY_P)) { + *flags &=3D ~PAGE_WRITE; + } + if (VADDR_SEGMENT_TL(vaddr) < (entry & REGION_ENTRY_TF) >> 6 || + VADDR_SEGMENT_TL(vaddr) > (entry & REGION_ENTRY_TL)) { + return PGM_SEGMENT_TRANS; + } + gaddr =3D (entry & REGION_ENTRY_ORIGIN) + VADDR_SEGMENT_TX(vaddr) = * 8; + /* fall through */ + case ASCE_TYPE_SEGMENT: + if (read_table_entry(gaddr, &entry)) { + return PGM_ADDRESSING; + } + if (entry & SEGMENT_ENTRY_I) { + return PGM_SEGMENT_TRANS; + } + if ((entry & SEGMENT_ENTRY_TT) !=3D SEGMENT_ENTRY_TT_SEGMENT) { + return PGM_TRANS_SPEC; + } + if ((entry & SEGMENT_ENTRY_CS) && asce_p) { + return PGM_TRANS_SPEC; + } + if (entry & SEGMENT_ENTRY_P) { + *flags &=3D ~PAGE_WRITE; + } + if (edat1 && (entry & SEGMENT_ENTRY_FC)) { + *raddr =3D (entry & SEGMENT_ENTRY_SFAA) | + (vaddr & ~SEGMENT_ENTRY_SFAA); + return 0; + } + gaddr =3D (entry & SEGMENT_ENTRY_ORIGIN) + VADDR_PAGE_TX(vaddr) * = 8; break; + default: + g_assert_not_reached(); + } + + if (read_table_entry(gaddr, &entry)) { + return PGM_ADDRESSING; + } + if (entry & PAGE_ENTRY_I) { + return PGM_PAGE_TRANS; + } + if (entry & PAGE_ENTRY_0) { + return PGM_TRANS_SPEC; + } + if (entry & PAGE_ENTRY_P) { + *flags &=3D ~PAGE_WRITE; } =20 - return mmu_translate_region(env, vaddr, asc, asce, level, raddr, flags= , rw, - exc); + *raddr =3D entry & TARGET_PAGE_MASK; + return 0; } =20 static void mmu_handle_skey(target_ulong addr, int rw, int *flags) --=20 2.21.0