From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from eggs.gnu.org ([2001:4830:134:3::10]:50280) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1YB3hi-00044p-Go for qemu-devel@nongnu.org; Tue, 13 Jan 2015 10:48:27 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1YB3hf-0003mC-IY for qemu-devel@nongnu.org; Tue, 13 Jan 2015 10:48:26 -0500 Received: from mx1.redhat.com ([209.132.183.28]:50599) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1YB3hf-0003lC-By for qemu-devel@nongnu.org; Tue, 13 Jan 2015 10:48:23 -0500 From: Andrew Jones Date: Tue, 13 Jan 2015 16:48:11 +0100 Message-Id: <1421164091-19989-3-git-send-email-drjones@redhat.com> In-Reply-To: <1421164091-19989-1-git-send-email-drjones@redhat.com> References: <1421164091-19989-1-git-send-email-drjones@redhat.com> Subject: [Qemu-devel] [PATCH 2/2] tcg-arm: more instruction execution control List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , To: qemu-devel@nongnu.org Cc: peter.maydell@linaro.org Cleanup XN/PXN handling in get_phys_addr_lpae, and implement all but EL2 support of the following ARMv8 sections D4.5.1 Memory access control: Access permissions for instruction execution G4.7.2 Execute-never restrictions on instruction fetching G4.7.2 matches the ARMv7 section B3.7.2 when long-descriptors are used. Signed-off-by: Andrew Jones --- v3: - correct logic for (is_user && !(ap & 1)) case - base on "user doesn't need R/W access to exec" patch v2: correct assert in el2 case I didn't test this with secure mode (I didn't even check if that's currently possible), but I did test all other EL1&0 XN controls with both tcg-arm (cortex-a15) and tcg-aarch64 (cortex-a57) by hacking up some tests with kvm-unit-tests/arm[64]. I also booted Linux (just up to looking for a rootfs) with both. target-arm/helper.c | 80 +++++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 66 insertions(+), 14 deletions(-) diff --git a/target-arm/helper.c b/target-arm/helper.c index 7c30a2669a0f2..715e0f47bec7d 100644 --- a/target-arm/helper.c +++ b/target-arm/helper.c @@ -4516,6 +4516,69 @@ static inline int check_ap(CPUARMState *env, int ap, int domain_prot, } } +/* Check section/page execution permission. + * + * Returns PAGE_EXEC if execution is permitted, otherwise zero. + * + * Supports AArch64, AArch32, and v7-LPAE. Doesn't yet support + * EL2. Actually, for v7-LPAE, we'd also need to emulate Virt + * Extensions to truly have WXN/UWXN. We don't support checking + * for that yet, so we just assume we have them. + * + * @env : CPUARMState + * @is_user : 0 for privileged access, 1 for user + * @ap : Access permissions (AP[2:1]) from descriptor + * @ns : (NSTable || NS) from descriptors + * @xn : ([U]XNTable || [U]XN) from descriptors + * @pxn : (PXNTable || PXN) from descriptors + */ +static int check_xn_lpae(CPUARMState *env, int is_user, int ap, + int ns, int xn, int pxn) +{ + int wxn; + + switch (arm_current_el(env)) { + case 0: + case 1: + wxn = env->cp15.sctlr_el[1] & SCTLR_WXN; + if (arm_el_is_aa64(env, 1)) { + if (is_user && !(ap & 1)) { + wxn = 0; + } + pxn = pxn || ((ap & 1) && !(ap & 2)); + xn = is_user ? xn : pxn; + } else { + int uwxn = env->cp15.sctlr_el[1] & SCTLR_UWXN; + pxn = pxn || (uwxn && (ap & 1) && !(ap & 2)); + xn = xn || (!is_user && pxn) || (is_user && !(ap & 1)); + } + if (arm_is_secure(env)) { + xn = xn || (ns && (env->cp15.scr_el3 & SCR_SIF)); + } + break; + case 2: + /* TODO actually support EL2 */ + assert(false); + + if (arm_el_is_aa64(env, 2)) { + wxn = env->cp15.sctlr_el[2] & SCTLR_WXN; + } else { + /* wxn = HSCTLR.WXN */ + } + break; + case 3: + if (arm_el_is_aa64(env, 3)) { + wxn = env->cp15.sctlr_el[3] & SCTLR_WXN; + } else { + wxn = 0; + } + xn = xn || (ns && (env->cp15.scr_el3 & SCR_SIF)); + break; + } + + return xn || (!(ap & 2) && wxn) ? 0 : PAGE_EXEC; +} + static bool get_level1_table_address(CPUARMState *env, uint32_t *table, uint32_t address) { @@ -4941,7 +5004,7 @@ static int get_phys_addr_lpae(CPUARMState *env, target_ulong address, if (extract32(tableattrs, 2, 1)) { attrs &= ~(1 << 4); } - /* Since we're always in the Non-secure state, NSTable is ignored. */ + attrs |= extract32(tableattrs, 4, 1) << 3; /* NS */ break; } /* Here descaddr is the final physical address, and attributes @@ -4962,19 +5025,8 @@ static int get_phys_addr_lpae(CPUARMState *env, target_ulong address, *prot |= !(ap & 2) ? PAGE_WRITE : 0; } - *prot |= PAGE_EXEC; - if ((arm_feature(env, ARM_FEATURE_V8) && is_user && (attrs & (1 << 12))) || - (!arm_feature(env, ARM_FEATURE_V8) && (attrs & (1 << 12))) || - (!arm_el_is_aa64(env, 1) && is_user && !(ap & 1)) || - (!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; - } + *prot |= check_xn_lpae(env, is_user, ap, extract32(attrs, 3, 1), + extract32(attrs, 12, 1), extract32(attrs, 11, 1)); if ((*prot == 0) || (!(*prot & PAGE_WRITE) && access_type == 1) -- 1.9.3