From patchwork Thu Feb 12 15:05:06 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Andrew Jones X-Patchwork-Id: 439238 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.gnu.org (lists.gnu.org [IPv6:2001:4830:134:3::11]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id D4C0B14008F for ; Fri, 13 Feb 2015 02:18:46 +1100 (AEDT) Received: from localhost ([::1]:50707 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1YLvXQ-0006gS-Qy for incoming@patchwork.ozlabs.org; Thu, 12 Feb 2015 10:18:44 -0500 Received: from eggs.gnu.org ([2001:4830:134:3::10]:46670) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1YLvX8-0006Pw-Bd for qemu-devel@nongnu.org; Thu, 12 Feb 2015 10:18:27 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1YLvX5-0002ML-55 for qemu-devel@nongnu.org; Thu, 12 Feb 2015 10:18:26 -0500 Received: from mx1.redhat.com ([209.132.183.28]:40983) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1YLvX4-0002M2-Ue for qemu-devel@nongnu.org; Thu, 12 Feb 2015 10:18:23 -0500 Received: from int-mx14.intmail.prod.int.phx2.redhat.com (int-mx14.intmail.prod.int.phx2.redhat.com [10.5.11.27]) by mx1.redhat.com (8.14.4/8.14.4) with ESMTP id t1CFIGTw027025 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=FAIL); Thu, 12 Feb 2015 10:18:21 -0500 Received: from hawk.usersys.redhat.com ([10.34.1.145]) by int-mx14.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with ESMTP id t1CF5BVR019602; Thu, 12 Feb 2015 10:05:18 -0500 From: Andrew Jones To: qemu-devel@nongnu.org Date: Thu, 12 Feb 2015 16:05:06 +0100 Message-Id: <1423753507-30542-5-git-send-email-drjones@redhat.com> In-Reply-To: <1423753507-30542-1-git-send-email-drjones@redhat.com> References: <1423753507-30542-1-git-send-email-drjones@redhat.com> X-Scanned-By: MIMEDefang 2.68 on 10.5.11.27 X-detected-operating-system: by eggs.gnu.org: GNU/Linux 3.x X-Received-From: 209.132.183.28 Cc: peter.maydell@linaro.org Subject: [Qemu-devel] [PATCH 4/5] target-arm: get_phys_addr_lpae: more xn control 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 This patch makes the following changes to the determination of whether an address is executable, when translating addresses using LPAE. 1. No longer assumes that PL0 can't execute when it can't read. It can in AArch64, a difference from AArch32. 2. Use va_size == 64 to determine we're in AArch64, rather than arm_feature(env, ARM_FEATURE_V8), which is insufficient. 3. Add additional XN determinants - NS && is_secure && (SCR & SCR_SIF) - WXN && (prot & PAGE_WRITE) - AArch64: (prot_PL0 & PAGE_WRITE) - AArch32: UWXN && (prot_PL0 & PAGE_WRITE) - XN determination should also work in secure mode (untested) - XN may even work in EL2 (currently impossible to test) 4. Cleans up the bloated PAGE_EXEC condition - by removing it. The helper get_S1prot is introduced, which also handles short- descriptors and v6 XN determination. It may even work in EL2, when support for that comes, but, as the function name implies, it only works for stage 1 translations. Signed-off-by: Andrew Jones --- target-arm/helper.c | 111 ++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 86 insertions(+), 25 deletions(-) diff --git a/target-arm/helper.c b/target-arm/helper.c index df78f481e92f4..20e5753bd216d 100644 --- a/target-arm/helper.c +++ b/target-arm/helper.c @@ -4695,8 +4695,8 @@ static inline bool regime_is_user(CPUARMState *env, ARMMMUIdx mmu_idx) /* Translate section/page access permissions to page * R/W protection flags */ -static inline int get_rw_prot(CPUARMState *env, ARMMMUIdx mmu_idx, - bool is_user, int ap, int domain_prot) +static int get_rw_prot(CPUARMState *env, ARMMMUIdx mmu_idx, + bool is_user, int ap, int domain_prot) { bool simple_ap = regime_using_lpae_format(env, mmu_idx) || (regime_sctlr(env, mmu_idx) & SCTLR_AFE); @@ -4762,6 +4762,84 @@ static inline int get_rw_prot(CPUARMState *env, ARMMMUIdx mmu_idx, } } +/* Translate section/page access permissions to protection flags */ +static int get_S1prot(CPUARMState *env, ARMMMUIdx mmu_idx, bool is_aa64, + int ap, int domain_prot, int ns, int xn, int pxn) +{ + bool domain_prot_valid = !regime_using_lpae_format(env, mmu_idx); + bool is_user = regime_is_user(env, mmu_idx); + bool have_wxn; + int prot_rw, user_rw; + int wxn = 0; + + assert(mmu_idx != ARMMMUIdx_S2NS); + + if (domain_prot_valid && domain_prot == 3) { + return PAGE_READ | PAGE_WRITE | PAGE_EXEC; + } + + user_rw = get_rw_prot(env, mmu_idx, true, ap, domain_prot); + if (is_user) { + prot_rw = user_rw; + } else { + prot_rw = get_rw_prot(env, mmu_idx, false, ap, domain_prot); + } + + if (ns && arm_is_secure(env) && (env->cp15.scr_el3 & SCR_SIF)) { + return prot_rw; + } + + /* TODO have_wxn should be replaced with arm_feature(env, ARM_FEATURE_EL2), + * when ARM_FEATURE_EL2 starts getting set. For now we assume all v7 + * compatible processors have EL2, which is required for [U]WXN. + */ + have_wxn = arm_feature(env, ARM_FEATURE_V7); + + if (have_wxn) { + wxn = regime_sctlr(env, mmu_idx) & SCTLR_WXN; + } + + if (is_aa64) { + assert(arm_feature(env, ARM_FEATURE_V8)); + switch (regime_el(env, mmu_idx)) { + case 1: + if (is_user && !user_rw) { + wxn = 0; + } else if (!is_user) { + xn = pxn || (user_rw & PAGE_WRITE); + } + break; + case 2: + case 3: + break; + } + } else if (arm_feature(env, ARM_FEATURE_V6K)) { + switch (regime_el(env, mmu_idx)) { + case 1: + case 3: + if (is_user) { + xn = xn || !user_rw; + } else { + int uwxn = 0; + if (have_wxn) { + uwxn = regime_sctlr(env, mmu_idx) & SCTLR_UWXN; + } + xn = xn || !prot_rw || pxn || (uwxn && (user_rw & PAGE_WRITE)); + } + break; + case 2: + break; + } + } else { + xn = wxn = 0; + } + + if (xn || (wxn && (prot_rw & PAGE_WRITE))) { + return prot_rw; + } + return prot_rw | PAGE_EXEC; +} + static bool get_level1_table_address(CPUARMState *env, ARMMMUIdx mmu_idx, uint32_t *table, uint32_t address) { @@ -5047,7 +5125,6 @@ static int get_phys_addr_lpae(CPUARMState *env, target_ulong address, int32_t granule_sz = 9; int32_t va_size = 32; int32_t tbi = 0; - bool is_user; TCR *tcr = regime_tcr(env, mmu_idx); /* TODO: @@ -5220,31 +5297,15 @@ static int get_phys_addr_lpae(CPUARMState *env, target_ulong address, /* Access flag */ goto do_fault; } + + *prot = get_S1prot(env, mmu_idx, va_size == 64, extract32(attrs, 4, 2), 0, + extract32(attrs, 3, 1), extract32(attrs, 12, 1), + extract32(attrs, 11, 1)); + fault_type = permission_fault; - is_user = regime_is_user(env, mmu_idx); - if (is_user && !(attrs & (1 << 4))) { - /* Unprivileged access not enabled */ + if (!(*prot & (1 << access_type))) { goto do_fault; } - *prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC; - if ((arm_feature(env, ARM_FEATURE_V8) && is_user && (attrs & (1 << 12))) || - (!arm_feature(env, ARM_FEATURE_V8) && (attrs & (1 << 12))) || - (!is_user && (attrs & (1 << 11)))) { - /* XN/UXN or PXN. Since we only implement EL0/EL1 we unconditionally - * treat XN/UXN as UXN for v8. - */ - if (access_type == 2) { - goto do_fault; - } - *prot &= ~PAGE_EXEC; - } - if (attrs & (1 << 5)) { - /* Write access forbidden */ - if (access_type == 1) { - goto do_fault; - } - *prot &= ~PAGE_WRITE; - } *phys_ptr = descaddr; *page_size_ptr = page_size;