From patchwork Fri Jun 4 15:52:05 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Alex_Benn=C3=A9e?= X-Patchwork-Id: 454100 Delivered-To: patch@linaro.org Received: by 2002:a02:735a:0:0:0:0:0 with SMTP id a26csp580216jae; Fri, 4 Jun 2021 09:46:52 -0700 (PDT) X-Google-Smtp-Source: ABdhPJyErF9GB3vzCHN9Nya6atGbo9lRggN1J5W/8mVGHY+eLGiWLglPJTaN2+lA0a2v9S8+FKdm X-Received: by 2002:ab0:2811:: with SMTP id w17mr4272491uap.34.1622825212410; Fri, 04 Jun 2021 09:46:52 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1622825212; cv=none; d=google.com; s=arc-20160816; b=RNSoi5wshfXB4yOmf+6Cyfk+S8pQZGnBB0zsv85DmB2aSwQPcVwEAjIOgk+XYmNk5r GulMvLik9U+W7FuAckQZq5fcvmLW0pUxrtrWnSN9WiGeI0BDxvIwzGxhdpg8iATBCaH2 toH8VgTtA8592AgspuY2SRWrJOJq7JJPPUe4aIGglFQ8fxqBIRJJQ2NeQVnLzzxeFZvw Ua6j/Z1VogfK5BupsFF1RnqGWusxY4nuhGFTdnmMijg7i4opE3GVDER/yF2QV/TTzKI1 fkrVO5/xYF7DzI0yQTrF++kbUWav+4Zd+/PK+q+FcwSHkBBEeW5w1zUzPu6f8sluzsnN LaqQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=sender:errors-to:cc:list-subscribe:list-help:list-post:list-archive :list-unsubscribe:list-id:precedence:content-transfer-encoding :mime-version:references:in-reply-to:message-id:date:subject:to:from :dkim-signature; bh=cQ2ujkUUxMglVlDp0hN1+qrHfRzklbjMoNxNds9wJe8=; b=tsstp07icLjTDB8byruSruMTXuGHk3Gzq0MABWh5xYwyn3xz3AKHC2qI8D/XYDzQbz g8M0Cj2csVGgw1kd+INTtaizl9RZM3nORj3ax/0SPiZvsEDtQUynR1u7hVzGGfiFnouH 23TieVE6VVz/KxvB02pFUBaGK3JopGBzagKXajScxOmi5H7EQf1eZyl6QS+ZoJ0hqA31 rzq3HwAe1KLUJcppsk9ZNKXzXMXpU+ZNh+IMxp9z833fBhOMy8vyXejaBxjuYyBpfWf6 MBNNttqkpYVobdockGHrNPvqntDG6pBEEx4dNbdD3VBbwsUJ7aYoTNPuGtDc3C1BGIT8 vBzw== ARC-Authentication-Results: i=1; mx.google.com; dkim=fail header.i=@linaro.org header.s=google header.b=MunX7wJy; spf=pass (google.com: domain of qemu-devel-bounces+patch=linaro.org@nongnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom="qemu-devel-bounces+patch=linaro.org@nongnu.org"; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=linaro.org Return-Path: Received: from lists.gnu.org (lists.gnu.org. [209.51.188.17]) by mx.google.com with ESMTPS id s191si3139213vsc.101.2021.06.04.09.46.52 for (version=TLS1_2 cipher=ECDHE-ECDSA-CHACHA20-POLY1305 bits=256/256); Fri, 04 Jun 2021 09:46:52 -0700 (PDT) Received-SPF: pass (google.com: domain of qemu-devel-bounces+patch=linaro.org@nongnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; Authentication-Results: mx.google.com; dkim=fail header.i=@linaro.org header.s=google header.b=MunX7wJy; spf=pass (google.com: domain of qemu-devel-bounces+patch=linaro.org@nongnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom="qemu-devel-bounces+patch=linaro.org@nongnu.org"; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=linaro.org Received: from localhost ([::1]:44424 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1lpCyB-0003VX-O7 for patch@linaro.org; Fri, 04 Jun 2021 12:46:51 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:48700) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1lpCIC-00004y-Jd for qemu-devel@nongnu.org; Fri, 04 Jun 2021 12:03:29 -0400 Received: from mail-wm1-x32d.google.com ([2a00:1450:4864:20::32d]:43961) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1lpCHm-0005vb-TY for qemu-devel@nongnu.org; Fri, 04 Jun 2021 12:03:28 -0400 Received: by mail-wm1-x32d.google.com with SMTP id 3-20020a05600c0243b029019f2f9b2b8aso5901890wmj.2 for ; Fri, 04 Jun 2021 09:03:01 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=cQ2ujkUUxMglVlDp0hN1+qrHfRzklbjMoNxNds9wJe8=; b=MunX7wJysLY09AHzntU+rLHcprV9jFfSAE39+dP0Eh5PnMCxtJTB93rmun2c5Gjesh /hGkWMqW70Mx0C2E8a7r6evcWfT5N3QuVCVpMrHpl1PmJYnNzt2EiaVN1fH0eySaoxIB 5CnamhDHDazJmamWDOEQmGXTpaHpvyg9METK1GlzRDwT/aUb/CzGKTKuB3b3O0UIQg7i 9nUgykAfYKwrygtAy2zgsthNdduBZyUwMXjVFSEW9K6JOpXwCw6JlV+Y3LmPh8Klmo+s 5oBcBR2uY4ZL+HD5rvu8M0F7typmXzUwd1e/ultDHwi6tiQX3/jpcyVNYalvf0r3pqBt mEcg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=cQ2ujkUUxMglVlDp0hN1+qrHfRzklbjMoNxNds9wJe8=; b=AV2f6KC+MZPD528E+0H1HvHRalV/8Ic0peJ0uZ9Z5yu1tqPt7+GbVoCJOF6PQY19BF N5c02T/fwE21qiNymFm0ohVJwUK62joW1hRPPDC3febqyxlTSkyMHu1MaRrbcM6sEYio R7PJ/DwQicwFtySVBLAuwhiaohgmxcmDJQT12J7iGj76nc1jMc9mIAVvSOqpIZ3D3JDF YMQTLAQgkyicUVBLcwBQMEu/xGN0rsowVmX7EffQGGsfxQ9eIUrmTZWEqRdtycUfR6cF 1kuRvm34dKZyZ7aMFZ/tkGWJIQlysRQLKlCR9xx9imjBUcu1GtzgNIVvJfKInQRnWoWH 86pw== X-Gm-Message-State: AOAM531dHlKfAY/5wTDgVByc3bnV30vIx6y0ev9p6H7D07TJlLV/Ryzw J2VWXm994Wh/z88Md69u0E9PMTy2Wyx3SQ== X-Received: by 2002:a7b:c935:: with SMTP id h21mr4334812wml.183.1622822580448; Fri, 04 Jun 2021 09:03:00 -0700 (PDT) Received: from zen.linaroharston ([51.148.130.216]) by smtp.gmail.com with ESMTPSA id z3sm7565593wrl.13.2021.06.04.09.02.48 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 04 Jun 2021 09:02:56 -0700 (PDT) Received: from zen.lan (localhost [127.0.0.1]) by zen.linaroharston (Postfix) with ESMTP id E95011FFB8; Fri, 4 Jun 2021 16:53:16 +0100 (BST) From: =?utf-8?q?Alex_Benn=C3=A9e?= To: qemu-devel@nongnu.org Subject: [PATCH v16 32/99] target/arm: move cpsr_read, cpsr_write to cpu_common Date: Fri, 4 Jun 2021 16:52:05 +0100 Message-Id: <20210604155312.15902-33-alex.bennee@linaro.org> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20210604155312.15902-1-alex.bennee@linaro.org> References: <20210604155312.15902-1-alex.bennee@linaro.org> MIME-Version: 1.0 Received-SPF: pass client-ip=2a00:1450:4864:20::32d; envelope-from=alex.bennee@linaro.org; helo=mail-wm1-x32d.google.com X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=unavailable autolearn_force=no X-Spam_action: no action 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: =?utf-8?q?Alex_Benn=C3=A9e?= , qemu-arm@nongnu.org, Richard Henderson , Claudio Fontana , Peter Maydell Errors-To: qemu-devel-bounces+patch=linaro.org@nongnu.org Sender: "Qemu-devel" From: Claudio Fontana we need as a result to move switch_mode too, so we put an implementation into cpu_user and cpu_sysemu. Signed-off-by: Claudio Fontana Reviewed-by: Richard Henderson Signed-off-by: Alex Bennée --- target/arm/cpu.h | 2 + target/arm/cpu-common.c | 192 +++++++++++++++++++++++++++++++++++ target/arm/cpu-sysemu.c | 30 ++++++ target/arm/cpu-user.c | 24 +++++ target/arm/tcg/helper.c | 220 ---------------------------------------- target/arm/meson.build | 3 + 6 files changed, 251 insertions(+), 220 deletions(-) create mode 100644 target/arm/cpu-user.c -- 2.20.1 diff --git a/target/arm/cpu.h b/target/arm/cpu.h index adb9d2828d..c5ead3365f 100644 --- a/target/arm/cpu.h +++ b/target/arm/cpu.h @@ -1390,6 +1390,8 @@ typedef enum CPSRWriteType { void cpsr_write(CPUARMState *env, uint32_t val, uint32_t mask, CPSRWriteType write_type); +void switch_mode(CPUARMState *env, int mode); + /* Return the current xPSR value. */ static inline uint32_t xpsr_read(CPUARMState *env) { diff --git a/target/arm/cpu-common.c b/target/arm/cpu-common.c index 0f8ca94815..694e5d73f3 100644 --- a/target/arm/cpu-common.c +++ b/target/arm/cpu-common.c @@ -7,10 +7,12 @@ */ #include "qemu/osdep.h" +#include "qemu/log.h" #include "qom/object.h" #include "qapi/qapi-commands-machine-target.h" #include "qapi/error.h" #include "cpu.h" +#include "internals.h" static void arm_cpu_add_definition(gpointer data, gpointer user_data) { @@ -39,3 +41,193 @@ CpuDefinitionInfoList *qmp_query_cpu_definitions(Error **errp) return cpu_list; } + +uint32_t cpsr_read(CPUARMState *env) +{ + int ZF; + ZF = (env->ZF == 0); + return env->uncached_cpsr | (env->NF & 0x80000000) | (ZF << 30) | + (env->CF << 29) | ((env->VF & 0x80000000) >> 3) | (env->QF << 27) + | (env->thumb << 5) | ((env->condexec_bits & 3) << 25) + | ((env->condexec_bits & 0xfc) << 8) + | (env->GE << 16) | (env->daif & CPSR_AIF); +} + +static int bad_mode_switch(CPUARMState *env, int mode, CPSRWriteType write_type) +{ + /* + * Return true if it is not valid for us to switch to + * this CPU mode (ie all the UNPREDICTABLE cases in + * the ARM ARM CPSRWriteByInstr pseudocode). + */ + + /* Changes to or from Hyp via MSR and CPS are illegal. */ + if (write_type == CPSRWriteByInstr && + ((env->uncached_cpsr & CPSR_M) == ARM_CPU_MODE_HYP || + mode == ARM_CPU_MODE_HYP)) { + return 1; + } + + switch (mode) { + case ARM_CPU_MODE_USR: + return 0; + case ARM_CPU_MODE_SYS: + case ARM_CPU_MODE_SVC: + case ARM_CPU_MODE_ABT: + case ARM_CPU_MODE_UND: + case ARM_CPU_MODE_IRQ: + case ARM_CPU_MODE_FIQ: + /* + * Note that we don't implement the IMPDEF NSACR.RFR which in v7 + * allows FIQ mode to be Secure-only. (In v8 this doesn't exist.) + * + * If HCR.TGE is set then changes from Monitor to NS PL1 via MSR + * and CPS are treated as illegal mode changes. + */ + if (write_type == CPSRWriteByInstr && + (env->uncached_cpsr & CPSR_M) == ARM_CPU_MODE_MON && + (arm_hcr_el2_eff(env) & HCR_TGE)) { + return 1; + } + return 0; + case ARM_CPU_MODE_HYP: + return !arm_is_el2_enabled(env) || arm_current_el(env) < 2; + case ARM_CPU_MODE_MON: + return arm_current_el(env) < 3; + default: + return 1; + } +} + +void cpsr_write(CPUARMState *env, uint32_t val, uint32_t mask, + CPSRWriteType write_type) +{ + uint32_t changed_daif; + + if (mask & CPSR_NZCV) { + env->ZF = (~val) & CPSR_Z; + env->NF = val; + env->CF = (val >> 29) & 1; + env->VF = (val << 3) & 0x80000000; + } + if (mask & CPSR_Q) { + env->QF = ((val & CPSR_Q) != 0); + } + if (mask & CPSR_T) { + env->thumb = ((val & CPSR_T) != 0); + } + if (mask & CPSR_IT_0_1) { + env->condexec_bits &= ~3; + env->condexec_bits |= (val >> 25) & 3; + } + if (mask & CPSR_IT_2_7) { + env->condexec_bits &= 3; + env->condexec_bits |= (val >> 8) & 0xfc; + } + if (mask & CPSR_GE) { + env->GE = (val >> 16) & 0xf; + } + + /* + * In a V7 implementation that includes the security extensions but does + * not include Virtualization Extensions the SCR.FW and SCR.AW bits control + * whether non-secure software is allowed to change the CPSR_F and CPSR_A + * bits respectively. + * + * In a V8 implementation, it is permitted for privileged software to + * change the CPSR A/F bits regardless of the SCR.AW/FW bits. + */ + if (write_type != CPSRWriteRaw && !arm_feature(env, ARM_FEATURE_V8) && + arm_feature(env, ARM_FEATURE_EL3) && + !arm_feature(env, ARM_FEATURE_EL2) && + !arm_is_secure(env)) { + + changed_daif = (env->daif ^ val) & mask; + + if (changed_daif & CPSR_A) { + /* + * Check to see if we are allowed to change the masking of async + * abort exceptions from a non-secure state. + */ + if (!(env->cp15.scr_el3 & SCR_AW)) { + qemu_log_mask(LOG_GUEST_ERROR, + "Ignoring attempt to switch CPSR_A flag from " + "non-secure world with SCR.AW bit clear\n"); + mask &= ~CPSR_A; + } + } + + if (changed_daif & CPSR_F) { + /* + * Check to see if we are allowed to change the masking of FIQ + * exceptions from a non-secure state. + */ + if (!(env->cp15.scr_el3 & SCR_FW)) { + qemu_log_mask(LOG_GUEST_ERROR, + "Ignoring attempt to switch CPSR_F flag from " + "non-secure world with SCR.FW bit clear\n"); + mask &= ~CPSR_F; + } + + /* + * Check whether non-maskable FIQ (NMFI) support is enabled. + * If this bit is set software is not allowed to mask + * FIQs, but is allowed to set CPSR_F to 0. + */ + if ((A32_BANKED_CURRENT_REG_GET(env, sctlr) & SCTLR_NMFI) && + (val & CPSR_F)) { + qemu_log_mask(LOG_GUEST_ERROR, + "Ignoring attempt to enable CPSR_F flag " + "(non-maskable FIQ [NMFI] support enabled)\n"); + mask &= ~CPSR_F; + } + } + } + + env->daif &= ~(CPSR_AIF & mask); + env->daif |= val & CPSR_AIF & mask; + + if (write_type != CPSRWriteRaw && + ((env->uncached_cpsr ^ val) & mask & CPSR_M)) { + if ((env->uncached_cpsr & CPSR_M) == ARM_CPU_MODE_USR) { + /* + * Note that we can only get here in USR mode if this is a + * gdb stub write; for this case we follow the architectural + * behaviour for guest writes in USR mode of ignoring an attempt + * to switch mode. (Those are caught by translate.c for writes + * triggered by guest instructions.) + */ + mask &= ~CPSR_M; + } else if (bad_mode_switch(env, val & CPSR_M, write_type)) { + /* + * Attempt to switch to an invalid mode: this is UNPREDICTABLE in + * v7, and has defined behaviour in v8: + * + leave CPSR.M untouched + * + allow changes to the other CPSR fields + * + set PSTATE.IL + * For user changes via the GDB stub, we don't set PSTATE.IL, + * as this would be unnecessarily harsh for a user error. + */ + mask &= ~CPSR_M; + if (write_type != CPSRWriteByGDBStub && + arm_feature(env, ARM_FEATURE_V8)) { + mask |= CPSR_IL; + val |= CPSR_IL; + } + qemu_log_mask(LOG_GUEST_ERROR, + "Illegal AArch32 mode switch attempt from %s to %s\n", + aarch32_mode_name(env->uncached_cpsr), + aarch32_mode_name(val)); + } else { + qemu_log_mask(CPU_LOG_INT, "%s %s to %s PC 0x%" PRIx32 "\n", + write_type == CPSRWriteExceptionReturn ? + "Exception return from AArch32" : + "AArch32 mode switch from", + aarch32_mode_name(env->uncached_cpsr), + aarch32_mode_name(val), env->regs[15]); + switch_mode(env, val & CPSR_M); + } + } + mask &= ~CACHED_CPSR_BITS; + env->uncached_cpsr = (env->uncached_cpsr & ~mask) | (val & mask); +} diff --git a/target/arm/cpu-sysemu.c b/target/arm/cpu-sysemu.c index db1c8cb245..3add2c2439 100644 --- a/target/arm/cpu-sysemu.c +++ b/target/arm/cpu-sysemu.c @@ -103,3 +103,33 @@ bool arm_cpu_virtio_is_big_endian(CPUState *cs) cpu_synchronize_state(cs); return arm_cpu_data_is_big_endian(env); } + +void switch_mode(CPUARMState *env, int mode) +{ + int old_mode; + int i; + + old_mode = env->uncached_cpsr & CPSR_M; + if (mode == old_mode) { + return; + } + + if (old_mode == ARM_CPU_MODE_FIQ) { + memcpy(env->fiq_regs, env->regs + 8, 5 * sizeof(uint32_t)); + memcpy(env->regs + 8, env->usr_regs, 5 * sizeof(uint32_t)); + } else if (mode == ARM_CPU_MODE_FIQ) { + memcpy(env->usr_regs, env->regs + 8, 5 * sizeof(uint32_t)); + memcpy(env->regs + 8, env->fiq_regs, 5 * sizeof(uint32_t)); + } + + i = bank_number(old_mode); + env->banked_r13[i] = env->regs[13]; + env->banked_spsr[i] = env->spsr; + + i = bank_number(mode); + env->regs[13] = env->banked_r13[i]; + env->spsr = env->banked_spsr[i]; + + env->banked_r14[r14_bank_number(old_mode)] = env->regs[14]; + env->regs[14] = env->banked_r14[r14_bank_number(mode)]; +} diff --git a/target/arm/cpu-user.c b/target/arm/cpu-user.c new file mode 100644 index 0000000000..a72b7f5703 --- /dev/null +++ b/target/arm/cpu-user.c @@ -0,0 +1,24 @@ +/* + * ARM CPU user-mode only code + * + * This code is licensed under the GNU GPL v2 or later. + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#include "qemu/osdep.h" +#include "qemu/log.h" +#include "qom/object.h" +#include "qapi/qapi-commands-machine-target.h" +#include "qapi/error.h" +#include "cpu.h" +#include "internals.h" + +void switch_mode(CPUARMState *env, int mode) +{ + ARMCPU *cpu = env_archcpu(env); + + if (mode != ARM_CPU_MODE_USR) { + cpu_abort(CPU(cpu), "Tried to switch out of user mode\n"); + } +} diff --git a/target/arm/tcg/helper.c b/target/arm/tcg/helper.c index f54ece9b42..d32f9659bc 100644 --- a/target/arm/tcg/helper.c +++ b/target/arm/tcg/helper.c @@ -38,8 +38,6 @@ #include "cpu-mmu.h" #include "cpregs.h" -static void switch_mode(CPUARMState *env, int mode); - static int vfp_gdb_get_reg(CPUARMState *env, GByteArray *buf, int reg) { ARMCPU *cpu = env_archcpu(env); @@ -696,186 +694,6 @@ void arm_cpu_list(void) g_slist_free(list); } -static int bad_mode_switch(CPUARMState *env, int mode, CPSRWriteType write_type) -{ - /* Return true if it is not valid for us to switch to - * this CPU mode (ie all the UNPREDICTABLE cases in - * the ARM ARM CPSRWriteByInstr pseudocode). - */ - - /* Changes to or from Hyp via MSR and CPS are illegal. */ - if (write_type == CPSRWriteByInstr && - ((env->uncached_cpsr & CPSR_M) == ARM_CPU_MODE_HYP || - mode == ARM_CPU_MODE_HYP)) { - return 1; - } - - switch (mode) { - case ARM_CPU_MODE_USR: - return 0; - case ARM_CPU_MODE_SYS: - case ARM_CPU_MODE_SVC: - case ARM_CPU_MODE_ABT: - case ARM_CPU_MODE_UND: - case ARM_CPU_MODE_IRQ: - case ARM_CPU_MODE_FIQ: - /* Note that we don't implement the IMPDEF NSACR.RFR which in v7 - * allows FIQ mode to be Secure-only. (In v8 this doesn't exist.) - */ - /* If HCR.TGE is set then changes from Monitor to NS PL1 via MSR - * and CPS are treated as illegal mode changes. - */ - if (write_type == CPSRWriteByInstr && - (env->uncached_cpsr & CPSR_M) == ARM_CPU_MODE_MON && - (arm_hcr_el2_eff(env) & HCR_TGE)) { - return 1; - } - return 0; - case ARM_CPU_MODE_HYP: - return !arm_is_el2_enabled(env) || arm_current_el(env) < 2; - case ARM_CPU_MODE_MON: - return arm_current_el(env) < 3; - default: - return 1; - } -} - -uint32_t cpsr_read(CPUARMState *env) -{ - int ZF; - ZF = (env->ZF == 0); - return env->uncached_cpsr | (env->NF & 0x80000000) | (ZF << 30) | - (env->CF << 29) | ((env->VF & 0x80000000) >> 3) | (env->QF << 27) - | (env->thumb << 5) | ((env->condexec_bits & 3) << 25) - | ((env->condexec_bits & 0xfc) << 8) - | (env->GE << 16) | (env->daif & CPSR_AIF); -} - -void cpsr_write(CPUARMState *env, uint32_t val, uint32_t mask, - CPSRWriteType write_type) -{ - uint32_t changed_daif; - - if (mask & CPSR_NZCV) { - env->ZF = (~val) & CPSR_Z; - env->NF = val; - env->CF = (val >> 29) & 1; - env->VF = (val << 3) & 0x80000000; - } - if (mask & CPSR_Q) - env->QF = ((val & CPSR_Q) != 0); - if (mask & CPSR_T) - env->thumb = ((val & CPSR_T) != 0); - if (mask & CPSR_IT_0_1) { - env->condexec_bits &= ~3; - env->condexec_bits |= (val >> 25) & 3; - } - if (mask & CPSR_IT_2_7) { - env->condexec_bits &= 3; - env->condexec_bits |= (val >> 8) & 0xfc; - } - if (mask & CPSR_GE) { - env->GE = (val >> 16) & 0xf; - } - - /* In a V7 implementation that includes the security extensions but does - * not include Virtualization Extensions the SCR.FW and SCR.AW bits control - * whether non-secure software is allowed to change the CPSR_F and CPSR_A - * bits respectively. - * - * In a V8 implementation, it is permitted for privileged software to - * change the CPSR A/F bits regardless of the SCR.AW/FW bits. - */ - if (write_type != CPSRWriteRaw && !arm_feature(env, ARM_FEATURE_V8) && - arm_feature(env, ARM_FEATURE_EL3) && - !arm_feature(env, ARM_FEATURE_EL2) && - !arm_is_secure(env)) { - - changed_daif = (env->daif ^ val) & mask; - - if (changed_daif & CPSR_A) { - /* Check to see if we are allowed to change the masking of async - * abort exceptions from a non-secure state. - */ - if (!(env->cp15.scr_el3 & SCR_AW)) { - qemu_log_mask(LOG_GUEST_ERROR, - "Ignoring attempt to switch CPSR_A flag from " - "non-secure world with SCR.AW bit clear\n"); - mask &= ~CPSR_A; - } - } - - if (changed_daif & CPSR_F) { - /* Check to see if we are allowed to change the masking of FIQ - * exceptions from a non-secure state. - */ - if (!(env->cp15.scr_el3 & SCR_FW)) { - qemu_log_mask(LOG_GUEST_ERROR, - "Ignoring attempt to switch CPSR_F flag from " - "non-secure world with SCR.FW bit clear\n"); - mask &= ~CPSR_F; - } - - /* Check whether non-maskable FIQ (NMFI) support is enabled. - * If this bit is set software is not allowed to mask - * FIQs, but is allowed to set CPSR_F to 0. - */ - if ((A32_BANKED_CURRENT_REG_GET(env, sctlr) & SCTLR_NMFI) && - (val & CPSR_F)) { - qemu_log_mask(LOG_GUEST_ERROR, - "Ignoring attempt to enable CPSR_F flag " - "(non-maskable FIQ [NMFI] support enabled)\n"); - mask &= ~CPSR_F; - } - } - } - - env->daif &= ~(CPSR_AIF & mask); - env->daif |= val & CPSR_AIF & mask; - - if (write_type != CPSRWriteRaw && - ((env->uncached_cpsr ^ val) & mask & CPSR_M)) { - if ((env->uncached_cpsr & CPSR_M) == ARM_CPU_MODE_USR) { - /* Note that we can only get here in USR mode if this is a - * gdb stub write; for this case we follow the architectural - * behaviour for guest writes in USR mode of ignoring an attempt - * to switch mode. (Those are caught by translate.c for writes - * triggered by guest instructions.) - */ - mask &= ~CPSR_M; - } else if (bad_mode_switch(env, val & CPSR_M, write_type)) { - /* Attempt to switch to an invalid mode: this is UNPREDICTABLE in - * v7, and has defined behaviour in v8: - * + leave CPSR.M untouched - * + allow changes to the other CPSR fields - * + set PSTATE.IL - * For user changes via the GDB stub, we don't set PSTATE.IL, - * as this would be unnecessarily harsh for a user error. - */ - mask &= ~CPSR_M; - if (write_type != CPSRWriteByGDBStub && - arm_feature(env, ARM_FEATURE_V8)) { - mask |= CPSR_IL; - val |= CPSR_IL; - } - qemu_log_mask(LOG_GUEST_ERROR, - "Illegal AArch32 mode switch attempt from %s to %s\n", - aarch32_mode_name(env->uncached_cpsr), - aarch32_mode_name(val)); - } else { - qemu_log_mask(CPU_LOG_INT, "%s %s to %s PC 0x%" PRIx32 "\n", - write_type == CPSRWriteExceptionReturn ? - "Exception return from AArch32" : - "AArch32 mode switch from", - aarch32_mode_name(env->uncached_cpsr), - aarch32_mode_name(val), env->regs[15]); - switch_mode(env, val & CPSR_M); - } - } - mask &= ~CACHED_CPSR_BITS; - env->uncached_cpsr = (env->uncached_cpsr & ~mask) | (val & mask); -} - /* Sign/zero extend */ uint32_t HELPER(sxtb16)(uint32_t x) { @@ -916,15 +734,6 @@ uint32_t HELPER(rbit)(uint32_t x) #ifdef CONFIG_USER_ONLY -static void switch_mode(CPUARMState *env, int mode) -{ - ARMCPU *cpu = env_archcpu(env); - - if (mode != ARM_CPU_MODE_USR) { - cpu_abort(CPU(cpu), "Tried to switch out of user mode\n"); - } -} - uint32_t arm_phys_excp_target_el(CPUState *cs, uint32_t excp_idx, uint32_t cur_el, bool secure) { @@ -938,35 +747,6 @@ void aarch64_sync_64_to_32(CPUARMState *env) #else -static void switch_mode(CPUARMState *env, int mode) -{ - int old_mode; - int i; - - old_mode = env->uncached_cpsr & CPSR_M; - if (mode == old_mode) - return; - - if (old_mode == ARM_CPU_MODE_FIQ) { - memcpy (env->fiq_regs, env->regs + 8, 5 * sizeof(uint32_t)); - memcpy (env->regs + 8, env->usr_regs, 5 * sizeof(uint32_t)); - } else if (mode == ARM_CPU_MODE_FIQ) { - memcpy (env->usr_regs, env->regs + 8, 5 * sizeof(uint32_t)); - memcpy (env->regs + 8, env->fiq_regs, 5 * sizeof(uint32_t)); - } - - i = bank_number(old_mode); - env->banked_r13[i] = env->regs[13]; - env->banked_spsr[i] = env->spsr; - - i = bank_number(mode); - env->regs[13] = env->banked_r13[i]; - env->spsr = env->banked_spsr[i]; - - env->banked_r14[r14_bank_number(old_mode)] = env->regs[14]; - env->regs[14] = env->banked_r14[r14_bank_number(mode)]; -} - /* Physical Interrupt Target EL Lookup Table * * [ From ARM ARM section G1.13.4 (Table G1-15) ] diff --git a/target/arm/meson.build b/target/arm/meson.build index 8d6177c1fb..1f7375375e 100644 --- a/target/arm/meson.build +++ b/target/arm/meson.build @@ -32,6 +32,9 @@ arm_softmmu_ss.add(when: 'CONFIG_TCG', if_true: files( )) arm_user_ss = ss.source_set() +arm_user_ss.add(files( + 'cpu-user.c', +)) subdir('tcg')