From nobody Mon May 13 12:20:01 2024 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=1562014955; cv=none; d=zoho.com; s=zohoarc; b=IWk89vC3J+OwCUlI602iCmjOS3C9He+HIOMKjyF9/UGpQEAGvVNbZljQh7dHSBaYdvAkVi+o/RcNDh0naDEPnRy0X8IVaci53sjkfuLvKCchtaZRD02F69/otG8zkt9mFRGSZW+U1nMKExp1vymlrqc/a1PPwDBzakech8RrvG0= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zoho.com; s=zohoarc; t=1562014955; h=Content-Type: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=qKmhHD5UbNdvPHp1xwcorRz+tFAIRdPDJkGE+M8P9bI=; b=OSLJ/P4ujsHalF62+X5b2cwqTlpYGDWfOK6hemscF7H0dGXy9XOGW33h6VNWywc7kxuvrq5xcreGMXTs/2xj7Wp2Bit9U/6OgmRLI4begq0JSVoJikurVIzR4c+KGKRMtseGesRDziWEqiFLAOD9rk7KXUlhja6gw6mWN7QBvI0= 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 (209.51.188.17 [209.51.188.17]) by mx.zohomail.com with SMTPS id 1562014955293944.192724138909; Mon, 1 Jul 2019 14:02:35 -0700 (PDT) Received: from localhost ([::1]:45490 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.86_2) (envelope-from ) id 1hi3RQ-0001Tj-2V for importer@patchew.org; Mon, 01 Jul 2019 17:02:24 -0400 Received: from [209.51.188.92] (port=43080 helo=eggs.gnu.org) by lists.gnu.org with esmtp (Exim 4.86_2) (envelope-from ) id 1hi3AX-000809-2e for qemu-devel@nongnu.org; Mon, 01 Jul 2019 16:45:00 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1hi3AP-00083W-BD for qemu-devel@nongnu.org; Mon, 01 Jul 2019 16:44:52 -0400 Received: from [209.132.183.28] (port=46292 helo=mx1.redhat.com) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1hi3AD-0007nS-6N; Mon, 01 Jul 2019 16:44:37 -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 79A8930BBE69; Mon, 1 Jul 2019 19:49:55 +0000 (UTC) Received: from x1w.redhat.com (unknown [10.40.205.170]) by smtp.corp.redhat.com (Postfix) with ESMTPS id 1D7E2379F; Mon, 1 Jul 2019 19:49:50 +0000 (UTC) From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= To: qemu-devel@nongnu.org Date: Mon, 1 Jul 2019 21:49:35 +0200 Message-Id: <20190701194942.10092-2-philmd@redhat.com> In-Reply-To: <20190701194942.10092-1-philmd@redhat.com> References: <20190701194942.10092-1-philmd@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]); Mon, 01 Jul 2019 19:50:00 +0000 (UTC) Content-Transfer-Encoding: quoted-printable X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] X-Received-From: 209.132.183.28 Subject: [Qemu-devel] [PATCH v4 1/8] target/arm: Move debug routines to debug_helper.c 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: Yang Zhong , Peter Maydell , Andrew Jones , Samuel Ortiz , Rob Bradford , =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= , Thomas Huth , qemu-arm@nongnu.org, Paolo Bonzini , =?UTF-8?q?Alex=20Benn=C3=A9e?= Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" Content-Type: text/plain; charset="utf-8" These routines are TCG specific. Signed-off-by: Philippe Mathieu-Daud=C3=A9 --- v4: get_phys_page_attrs_debug is not TCG specific (Peter) --- target/arm/Makefile.objs | 2 +- target/arm/cpu.c | 9 +- target/arm/debug_helper.c | 311 ++++++++++++++++++++++++++++++++++++++ target/arm/op_helper.c | 295 ------------------------------------ 4 files changed, 315 insertions(+), 302 deletions(-) create mode 100644 target/arm/debug_helper.c diff --git a/target/arm/Makefile.objs b/target/arm/Makefile.objs index 5c154f01c5..294433da88 100644 --- a/target/arm/Makefile.objs +++ b/target/arm/Makefile.objs @@ -32,7 +32,7 @@ target/arm/translate-sve.o: target/arm/decode-sve.inc.c target/arm/translate.o: target/arm/decode-vfp.inc.c target/arm/translate.o: target/arm/decode-vfp-uncond.inc.c =20 -obj-y +=3D tlb_helper.o +obj-y +=3D tlb_helper.o debug_helper.o obj-y +=3D translate.o op_helper.o obj-y +=3D crypto_helper.o obj-y +=3D iwmmxt_helper.o vec_helper.o neon_helper.o diff --git a/target/arm/cpu.c b/target/arm/cpu.c index f21261c8ff..ca718fb38f 100644 --- a/target/arm/cpu.c +++ b/target/arm/cpu.c @@ -2578,19 +2578,16 @@ static void arm_cpu_class_init(ObjectClass *oc, voi= d *data) cc->gdb_arch_name =3D arm_gdb_arch_name; cc->gdb_get_dynamic_xml =3D arm_gdb_get_dynamic_xml; cc->gdb_stop_before_watchpoint =3D true; - cc->debug_excp_handler =3D arm_debug_excp_handler; - cc->debug_check_watchpoint =3D arm_debug_check_watchpoint; -#if !defined(CONFIG_USER_ONLY) - cc->adjust_watchpoint_address =3D arm_adjust_watchpoint_address; -#endif - cc->disas_set_info =3D arm_disas_set_info; #ifdef CONFIG_TCG cc->tcg_initialize =3D arm_translate_init; cc->tlb_fill =3D arm_cpu_tlb_fill; + cc->debug_excp_handler =3D arm_debug_excp_handler; + cc->debug_check_watchpoint =3D arm_debug_check_watchpoint; #if !defined(CONFIG_USER_ONLY) cc->do_unaligned_access =3D arm_cpu_do_unaligned_access; cc->do_transaction_failed =3D arm_cpu_do_transaction_failed; + cc->adjust_watchpoint_address =3D arm_adjust_watchpoint_address; #endif /* CONFIG_TCG && !CONFIG_USER_ONLY */ #endif } diff --git a/target/arm/debug_helper.c b/target/arm/debug_helper.c new file mode 100644 index 0000000000..dde80273ff --- /dev/null +++ b/target/arm/debug_helper.c @@ -0,0 +1,311 @@ +/* + * ARM debug helpers. + * + * This code is licensed under the GNU GPL v2 or later. + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ +#include "qemu/osdep.h" +#include "cpu.h" +#include "internals.h" +#include "exec/exec-all.h" +#include "exec/helper-proto.h" + +/* Return true if the linked breakpoint entry lbn passes its checks */ +static bool linked_bp_matches(ARMCPU *cpu, int lbn) +{ + CPUARMState *env =3D &cpu->env; + uint64_t bcr =3D env->cp15.dbgbcr[lbn]; + int brps =3D extract32(cpu->dbgdidr, 24, 4); + int ctx_cmps =3D extract32(cpu->dbgdidr, 20, 4); + int bt; + uint32_t contextidr; + + /* + * Links to unimplemented or non-context aware breakpoints are + * CONSTRAINED UNPREDICTABLE: either behave as if disabled, or + * as if linked to an UNKNOWN context-aware breakpoint (in which + * case DBGWCR_EL1.LBN must indicate that breakpoint). + * We choose the former. + */ + if (lbn > brps || lbn < (brps - ctx_cmps)) { + return false; + } + + bcr =3D env->cp15.dbgbcr[lbn]; + + if (extract64(bcr, 0, 1) =3D=3D 0) { + /* Linked breakpoint disabled : generate no events */ + return false; + } + + bt =3D extract64(bcr, 20, 4); + + /* + * We match the whole register even if this is AArch32 using the + * short descriptor format (in which case it holds both PROCID and ASI= D), + * since we don't implement the optional v7 context ID masking. + */ + contextidr =3D extract64(env->cp15.contextidr_el[1], 0, 32); + + switch (bt) { + case 3: /* linked context ID match */ + if (arm_current_el(env) > 1) { + /* Context matches never fire in EL2 or (AArch64) EL3 */ + return false; + } + return (contextidr =3D=3D extract64(env->cp15.dbgbvr[lbn], 0, 32)); + case 5: /* linked address mismatch (reserved in AArch64) */ + case 9: /* linked VMID match (reserved if no EL2) */ + case 11: /* linked context ID and VMID match (reserved if no EL2) */ + default: + /* + * Links to Unlinked context breakpoints must generate no + * events; we choose to do the same for reserved values too. + */ + return false; + } + + return false; +} + +static bool bp_wp_matches(ARMCPU *cpu, int n, bool is_wp) +{ + CPUARMState *env =3D &cpu->env; + uint64_t cr; + int pac, hmc, ssc, wt, lbn; + /* + * Note that for watchpoints the check is against the CPU security + * state, not the S/NS attribute on the offending data access. + */ + bool is_secure =3D arm_is_secure(env); + int access_el =3D arm_current_el(env); + + if (is_wp) { + CPUWatchpoint *wp =3D env->cpu_watchpoint[n]; + + if (!wp || !(wp->flags & BP_WATCHPOINT_HIT)) { + return false; + } + cr =3D env->cp15.dbgwcr[n]; + if (wp->hitattrs.user) { + /* + * The LDRT/STRT/LDT/STT "unprivileged access" instructions sh= ould + * match watchpoints as if they were accesses done at EL0, eve= n if + * the CPU is at EL1 or higher. + */ + access_el =3D 0; + } + } else { + uint64_t pc =3D is_a64(env) ? env->pc : env->regs[15]; + + if (!env->cpu_breakpoint[n] || env->cpu_breakpoint[n]->pc !=3D pc)= { + return false; + } + cr =3D env->cp15.dbgbcr[n]; + } + /* + * The WATCHPOINT_HIT flag guarantees us that the watchpoint is + * enabled and that the address and access type match; for breakpoints + * we know the address matched; check the remaining fields, including + * linked breakpoints. We rely on WCR and BCR having the same layout + * for the LBN, SSC, HMC, PAC/PMC and is-linked fields. + * Note that some combinations of {PAC, HMC, SSC} are reserved and + * must act either like some valid combination or as if the watchpoint + * were disabled. We choose the former, and use this together with + * the fact that EL3 must always be Secure and EL2 must always be + * Non-Secure to simplify the code slightly compared to the full + * table in the ARM ARM. + */ + pac =3D extract64(cr, 1, 2); + hmc =3D extract64(cr, 13, 1); + ssc =3D extract64(cr, 14, 2); + + switch (ssc) { + case 0: + break; + case 1: + case 3: + if (is_secure) { + return false; + } + break; + case 2: + if (!is_secure) { + return false; + } + break; + } + + switch (access_el) { + case 3: + case 2: + if (!hmc) { + return false; + } + break; + case 1: + if (extract32(pac, 0, 1) =3D=3D 0) { + return false; + } + break; + case 0: + if (extract32(pac, 1, 1) =3D=3D 0) { + return false; + } + break; + default: + g_assert_not_reached(); + } + + wt =3D extract64(cr, 20, 1); + lbn =3D extract64(cr, 16, 4); + + if (wt && !linked_bp_matches(cpu, lbn)) { + return false; + } + + return true; +} + +static bool check_watchpoints(ARMCPU *cpu) +{ + CPUARMState *env =3D &cpu->env; + int n; + + /* + * If watchpoints are disabled globally or we can't take debug + * exceptions here then watchpoint firings are ignored. + */ + if (extract32(env->cp15.mdscr_el1, 15, 1) =3D=3D 0 + || !arm_generate_debug_exceptions(env)) { + return false; + } + + for (n =3D 0; n < ARRAY_SIZE(env->cpu_watchpoint); n++) { + if (bp_wp_matches(cpu, n, true)) { + return true; + } + } + return false; +} + +static bool check_breakpoints(ARMCPU *cpu) +{ + CPUARMState *env =3D &cpu->env; + int n; + + /* + * If breakpoints are disabled globally or we can't take debug + * exceptions here then breakpoint firings are ignored. + */ + if (extract32(env->cp15.mdscr_el1, 15, 1) =3D=3D 0 + || !arm_generate_debug_exceptions(env)) { + return false; + } + + for (n =3D 0; n < ARRAY_SIZE(env->cpu_breakpoint); n++) { + if (bp_wp_matches(cpu, n, false)) { + return true; + } + } + return false; +} + +void HELPER(check_breakpoints)(CPUARMState *env) +{ + ARMCPU *cpu =3D env_archcpu(env); + + if (check_breakpoints(cpu)) { + HELPER(exception_internal(env, EXCP_DEBUG)); + } +} + +bool arm_debug_check_watchpoint(CPUState *cs, CPUWatchpoint *wp) +{ + /* + * Called by core code when a CPU watchpoint fires; need to check if t= his + * is also an architectural watchpoint match. + */ + ARMCPU *cpu =3D ARM_CPU(cs); + + return check_watchpoints(cpu); +} + +void arm_debug_excp_handler(CPUState *cs) +{ + /* + * Called by core code when a watchpoint or breakpoint fires; + * need to check which one and raise the appropriate exception. + */ + ARMCPU *cpu =3D ARM_CPU(cs); + CPUARMState *env =3D &cpu->env; + CPUWatchpoint *wp_hit =3D cs->watchpoint_hit; + + if (wp_hit) { + if (wp_hit->flags & BP_CPU) { + bool wnr =3D (wp_hit->flags & BP_WATCHPOINT_HIT_WRITE) !=3D 0; + bool same_el =3D arm_debug_target_el(env) =3D=3D arm_current_e= l(env); + + cs->watchpoint_hit =3D NULL; + + env->exception.fsr =3D arm_debug_exception_fsr(env); + env->exception.vaddress =3D wp_hit->hitaddr; + raise_exception(env, EXCP_DATA_ABORT, + syn_watchpoint(same_el, 0, wnr), + arm_debug_target_el(env)); + } + } else { + uint64_t pc =3D is_a64(env) ? env->pc : env->regs[15]; + bool same_el =3D (arm_debug_target_el(env) =3D=3D arm_current_el(e= nv)); + + /* + * (1) GDB breakpoints should be handled first. + * (2) Do not raise a CPU exception if no CPU breakpoint has fired, + * since singlestep is also done by generating a debug internal + * exception. + */ + if (cpu_breakpoint_test(cs, pc, BP_GDB) + || !cpu_breakpoint_test(cs, pc, BP_CPU)) { + return; + } + + env->exception.fsr =3D arm_debug_exception_fsr(env); + /* + * FAR is UNKNOWN: clear vaddress to avoid potentially exposing + * values to the guest that it shouldn't be able to see at its + * exception/security level. + */ + env->exception.vaddress =3D 0; + raise_exception(env, EXCP_PREFETCH_ABORT, + syn_breakpoint(same_el), + arm_debug_target_el(env)); + } +} + +#if !defined(CONFIG_USER_ONLY) + +vaddr arm_adjust_watchpoint_address(CPUState *cs, vaddr addr, int len) +{ + ARMCPU *cpu =3D ARM_CPU(cs); + CPUARMState *env =3D &cpu->env; + + /* + * In BE32 system mode, target memory is stored byteswapped (on a + * little-endian host system), and by the time we reach here (via an + * opcode helper) the addresses of subword accesses have been adjusted + * to account for that, which means that watchpoints will not match. + * Undo the adjustment here. + */ + if (arm_sctlr_b(env)) { + if (len =3D=3D 1) { + addr ^=3D 3; + } else if (len =3D=3D 2) { + addr ^=3D 2; + } + } + + return addr; +} + +#endif diff --git a/target/arm/op_helper.c b/target/arm/op_helper.c index 9850993c11..1ab91f915e 100644 --- a/target/arm/op_helper.c +++ b/target/arm/op_helper.c @@ -831,301 +831,6 @@ void HELPER(pre_smc)(CPUARMState *env, uint32_t syndr= ome) } } =20 -/* Return true if the linked breakpoint entry lbn passes its checks */ -static bool linked_bp_matches(ARMCPU *cpu, int lbn) -{ - CPUARMState *env =3D &cpu->env; - uint64_t bcr =3D env->cp15.dbgbcr[lbn]; - int brps =3D extract32(cpu->dbgdidr, 24, 4); - int ctx_cmps =3D extract32(cpu->dbgdidr, 20, 4); - int bt; - uint32_t contextidr; - - /* - * Links to unimplemented or non-context aware breakpoints are - * CONSTRAINED UNPREDICTABLE: either behave as if disabled, or - * as if linked to an UNKNOWN context-aware breakpoint (in which - * case DBGWCR_EL1.LBN must indicate that breakpoint). - * We choose the former. - */ - if (lbn > brps || lbn < (brps - ctx_cmps)) { - return false; - } - - bcr =3D env->cp15.dbgbcr[lbn]; - - if (extract64(bcr, 0, 1) =3D=3D 0) { - /* Linked breakpoint disabled : generate no events */ - return false; - } - - bt =3D extract64(bcr, 20, 4); - - /* - * We match the whole register even if this is AArch32 using the - * short descriptor format (in which case it holds both PROCID and ASI= D), - * since we don't implement the optional v7 context ID masking. - */ - contextidr =3D extract64(env->cp15.contextidr_el[1], 0, 32); - - switch (bt) { - case 3: /* linked context ID match */ - if (arm_current_el(env) > 1) { - /* Context matches never fire in EL2 or (AArch64) EL3 */ - return false; - } - return (contextidr =3D=3D extract64(env->cp15.dbgbvr[lbn], 0, 32)); - case 5: /* linked address mismatch (reserved in AArch64) */ - case 9: /* linked VMID match (reserved if no EL2) */ - case 11: /* linked context ID and VMID match (reserved if no EL2) */ - default: - /* - * Links to Unlinked context breakpoints must generate no - * events; we choose to do the same for reserved values too. - */ - return false; - } - - return false; -} - -static bool bp_wp_matches(ARMCPU *cpu, int n, bool is_wp) -{ - CPUARMState *env =3D &cpu->env; - uint64_t cr; - int pac, hmc, ssc, wt, lbn; - /* - * Note that for watchpoints the check is against the CPU security - * state, not the S/NS attribute on the offending data access. - */ - bool is_secure =3D arm_is_secure(env); - int access_el =3D arm_current_el(env); - - if (is_wp) { - CPUWatchpoint *wp =3D env->cpu_watchpoint[n]; - - if (!wp || !(wp->flags & BP_WATCHPOINT_HIT)) { - return false; - } - cr =3D env->cp15.dbgwcr[n]; - if (wp->hitattrs.user) { - /* - * The LDRT/STRT/LDT/STT "unprivileged access" instructions sh= ould - * match watchpoints as if they were accesses done at EL0, eve= n if - * the CPU is at EL1 or higher. - */ - access_el =3D 0; - } - } else { - uint64_t pc =3D is_a64(env) ? env->pc : env->regs[15]; - - if (!env->cpu_breakpoint[n] || env->cpu_breakpoint[n]->pc !=3D pc)= { - return false; - } - cr =3D env->cp15.dbgbcr[n]; - } - /* - * The WATCHPOINT_HIT flag guarantees us that the watchpoint is - * enabled and that the address and access type match; for breakpoints - * we know the address matched; check the remaining fields, including - * linked breakpoints. We rely on WCR and BCR having the same layout - * for the LBN, SSC, HMC, PAC/PMC and is-linked fields. - * Note that some combinations of {PAC, HMC, SSC} are reserved and - * must act either like some valid combination or as if the watchpoint - * were disabled. We choose the former, and use this together with - * the fact that EL3 must always be Secure and EL2 must always be - * Non-Secure to simplify the code slightly compared to the full - * table in the ARM ARM. - */ - pac =3D extract64(cr, 1, 2); - hmc =3D extract64(cr, 13, 1); - ssc =3D extract64(cr, 14, 2); - - switch (ssc) { - case 0: - break; - case 1: - case 3: - if (is_secure) { - return false; - } - break; - case 2: - if (!is_secure) { - return false; - } - break; - } - - switch (access_el) { - case 3: - case 2: - if (!hmc) { - return false; - } - break; - case 1: - if (extract32(pac, 0, 1) =3D=3D 0) { - return false; - } - break; - case 0: - if (extract32(pac, 1, 1) =3D=3D 0) { - return false; - } - break; - default: - g_assert_not_reached(); - } - - wt =3D extract64(cr, 20, 1); - lbn =3D extract64(cr, 16, 4); - - if (wt && !linked_bp_matches(cpu, lbn)) { - return false; - } - - return true; -} - -static bool check_watchpoints(ARMCPU *cpu) -{ - CPUARMState *env =3D &cpu->env; - int n; - - /* - * If watchpoints are disabled globally or we can't take debug - * exceptions here then watchpoint firings are ignored. - */ - if (extract32(env->cp15.mdscr_el1, 15, 1) =3D=3D 0 - || !arm_generate_debug_exceptions(env)) { - return false; - } - - for (n =3D 0; n < ARRAY_SIZE(env->cpu_watchpoint); n++) { - if (bp_wp_matches(cpu, n, true)) { - return true; - } - } - return false; -} - -static bool check_breakpoints(ARMCPU *cpu) -{ - CPUARMState *env =3D &cpu->env; - int n; - - /* - * If breakpoints are disabled globally or we can't take debug - * exceptions here then breakpoint firings are ignored. - */ - if (extract32(env->cp15.mdscr_el1, 15, 1) =3D=3D 0 - || !arm_generate_debug_exceptions(env)) { - return false; - } - - for (n =3D 0; n < ARRAY_SIZE(env->cpu_breakpoint); n++) { - if (bp_wp_matches(cpu, n, false)) { - return true; - } - } - return false; -} - -void HELPER(check_breakpoints)(CPUARMState *env) -{ - ARMCPU *cpu =3D env_archcpu(env); - - if (check_breakpoints(cpu)) { - HELPER(exception_internal(env, EXCP_DEBUG)); - } -} - -bool arm_debug_check_watchpoint(CPUState *cs, CPUWatchpoint *wp) -{ - /* - * Called by core code when a CPU watchpoint fires; need to check if t= his - * is also an architectural watchpoint match. - */ - ARMCPU *cpu =3D ARM_CPU(cs); - - return check_watchpoints(cpu); -} - -vaddr arm_adjust_watchpoint_address(CPUState *cs, vaddr addr, int len) -{ - ARMCPU *cpu =3D ARM_CPU(cs); - CPUARMState *env =3D &cpu->env; - - /* - * In BE32 system mode, target memory is stored byteswapped (on a - * little-endian host system), and by the time we reach here (via an - * opcode helper) the addresses of subword accesses have been adjusted - * to account for that, which means that watchpoints will not match. - * Undo the adjustment here. - */ - if (arm_sctlr_b(env)) { - if (len =3D=3D 1) { - addr ^=3D 3; - } else if (len =3D=3D 2) { - addr ^=3D 2; - } - } - - return addr; -} - -void arm_debug_excp_handler(CPUState *cs) -{ - /* - * Called by core code when a watchpoint or breakpoint fires; - * need to check which one and raise the appropriate exception. - */ - ARMCPU *cpu =3D ARM_CPU(cs); - CPUARMState *env =3D &cpu->env; - CPUWatchpoint *wp_hit =3D cs->watchpoint_hit; - - if (wp_hit) { - if (wp_hit->flags & BP_CPU) { - bool wnr =3D (wp_hit->flags & BP_WATCHPOINT_HIT_WRITE) !=3D 0; - bool same_el =3D arm_debug_target_el(env) =3D=3D arm_current_e= l(env); - - cs->watchpoint_hit =3D NULL; - - env->exception.fsr =3D arm_debug_exception_fsr(env); - env->exception.vaddress =3D wp_hit->hitaddr; - raise_exception(env, EXCP_DATA_ABORT, - syn_watchpoint(same_el, 0, wnr), - arm_debug_target_el(env)); - } - } else { - uint64_t pc =3D is_a64(env) ? env->pc : env->regs[15]; - bool same_el =3D (arm_debug_target_el(env) =3D=3D arm_current_el(e= nv)); - - /* - * (1) GDB breakpoints should be handled first. - * (2) Do not raise a CPU exception if no CPU breakpoint has fired, - * since singlestep is also done by generating a debug internal - * exception. - */ - if (cpu_breakpoint_test(cs, pc, BP_GDB) - || !cpu_breakpoint_test(cs, pc, BP_CPU)) { - return; - } - - env->exception.fsr =3D arm_debug_exception_fsr(env); - /* - * FAR is UNKNOWN: clear vaddress to avoid potentially exposing - * values to the guest that it shouldn't be able to see at its - * exception/security level. - */ - env->exception.vaddress =3D 0; - raise_exception(env, EXCP_PREFETCH_ABORT, - syn_breakpoint(same_el), - arm_debug_target_el(env)); - } -} - /* ??? Flag setting arithmetic is awkward because we need to do comparison= s. The only way to do that in TCG is a conditional branch, which clobbers all our temporaries. For now implement these as helper functions. */ --=20 2.20.1 From nobody Mon May 13 12:20:01 2024 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=1562031864; cv=none; d=zoho.com; s=zohoarc; b=T6mKTNABl9JHJQkRBHhxjf9ohf/UyHaEbfd1ZjOqcVK/+TAl3hMBkhY6KKqL8YmldHL886+tac+5FadpCTPmwr5S3re4165+f77aMlsXxFmNNiujoDBBQF9FmHFEda0w2534J/9lt0MZ2PG2p2lmAyy+PkqFmChODBTvTZS/eEM= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zoho.com; s=zohoarc; t=1562031864; h=Content-Type: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=dq1efkelonVdvO71YwtlbgErgi6LVcnrF/9y9hjGxuw=; b=X1KuCUtxYdD/tgnHQXPUNy8YMMJcFh9VcL+Lp650m7XxtFPFquPv6BXyjL5SAcn/b5LfRHULCXeDYrXyQOOQ8HTxbNWpcM4jA22+ASe+ej2SqEP1uIksbuAacfh5+cGL/byXaEaypNqqVPosIjD/0AF1AtELqJm82T4Msx8rrls= 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 1562031864170738.6545824127792; Mon, 1 Jul 2019 18:44:24 -0700 (PDT) Received: from localhost ([::1]:46998 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.86_2) (envelope-from ) id 1hi7qG-0006sO-6R for importer@patchew.org; Mon, 01 Jul 2019 21:44:20 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:47082) by lists.gnu.org with esmtp (Exim 4.86_2) (envelope-from ) id 1hi3xH-0000WT-AE for qemu-devel@nongnu.org; Mon, 01 Jul 2019 17:35:20 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1hi3xF-0002Ec-4o for qemu-devel@nongnu.org; Mon, 01 Jul 2019 17:35:19 -0400 Received: from mx1.redhat.com ([209.132.183.28]:50126) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1hi3xB-00021g-GE; Mon, 01 Jul 2019 17:35:13 -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 E399630C3192; Mon, 1 Jul 2019 19:49:59 +0000 (UTC) Received: from x1w.redhat.com (unknown [10.40.205.170]) by smtp.corp.redhat.com (Postfix) with ESMTPS id F2ABC87A0; Mon, 1 Jul 2019 19:49:55 +0000 (UTC) From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= To: qemu-devel@nongnu.org Date: Mon, 1 Jul 2019 21:49:36 +0200 Message-Id: <20190701194942.10092-3-philmd@redhat.com> In-Reply-To: <20190701194942.10092-1-philmd@redhat.com> References: <20190701194942.10092-1-philmd@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.40]); Mon, 01 Jul 2019 19:50:00 +0000 (UTC) Content-Transfer-Encoding: quoted-printable X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] X-Received-From: 209.132.183.28 Subject: [Qemu-devel] [PATCH v4 2/8] target/arm: Restrict semi-hosting to TCG 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: Yang Zhong , Peter Maydell , Andrew Jones , Samuel Ortiz , Rob Bradford , =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= , Thomas Huth , qemu-arm@nongnu.org, Paolo Bonzini , =?UTF-8?q?Alex=20Benn=C3=A9e?= Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" Content-Type: text/plain; charset="utf-8" Per Peter Maydell: Semihosting hooks either SVC or HLT instructions, and inside KVM both of those go to EL1, ie to the guest, and can't be trapped to KVM. Let check_for_semihosting() return False when not running on TCG. Signed-off-by: Philippe Mathieu-Daud=C3=A9 Reviewed-by: Peter Maydell --- v3: inline call to g_assert_not_reached if !TCG v4: fixed some ifdef that had moved in the next patch (Peter) --- target/arm/Makefile.objs | 2 +- target/arm/cpu.h | 7 +++++++ target/arm/helper.c | 8 +++++++- 3 files changed, 15 insertions(+), 2 deletions(-) diff --git a/target/arm/Makefile.objs b/target/arm/Makefile.objs index 294433da88..82bedefc3d 100644 --- a/target/arm/Makefile.objs +++ b/target/arm/Makefile.objs @@ -1,4 +1,4 @@ -obj-y +=3D arm-semi.o +obj-$(CONFIG_TCG) +=3D arm-semi.o obj-y +=3D helper.o vfp_helper.o obj-y +=3D cpu.o gdbstub.o obj-$(TARGET_AARCH64) +=3D cpu64.o gdbstub64.o diff --git a/target/arm/cpu.h b/target/arm/cpu.h index a9be18660f..94c990cddb 100644 --- a/target/arm/cpu.h +++ b/target/arm/cpu.h @@ -964,7 +964,14 @@ static inline void aarch64_sve_change_el(CPUARMState *= env, int o, { } #endif =20 +#if !defined(CONFIG_TCG) +static inline target_ulong do_arm_semihosting(CPUARMState *env) +{ + g_assert_not_reached(); +} +#else target_ulong do_arm_semihosting(CPUARMState *env); +#endif void aarch64_sync_32_to_64(CPUARMState *env); void aarch64_sync_64_to_32(CPUARMState *env); =20 diff --git a/target/arm/helper.c b/target/arm/helper.c index 38b73430cb..6d91e0a1f9 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -20,7 +20,6 @@ #include "qemu/qemu-print.h" #include "exec/exec-all.h" #include "exec/cpu_ldst.h" -#include "arm_ldst.h" #include /* For crc32 */ #include "hw/semihosting/semihost.h" #include "sysemu/cpus.h" @@ -29,6 +28,9 @@ #include "qapi/qapi-commands-target.h" #include "qapi/error.h" #include "qemu/guest-random.h" +#ifdef CONFIG_TCG +#include "arm_ldst.h" +#endif =20 #define ARM_CPU_FREQ 1000000000 /* FIXME: 1 GHz, should be configurable */ =20 @@ -10399,6 +10401,7 @@ static void arm_cpu_do_interrupt_aarch64(CPUState *= cs) =20 static inline bool check_for_semihosting(CPUState *cs) { +#ifdef CONFIG_TCG /* Check whether this exception is a semihosting call; if so * then handle it and return true; otherwise return false. */ @@ -10474,6 +10477,9 @@ static inline bool check_for_semihosting(CPUState *= cs) env->regs[0] =3D do_arm_semihosting(env); return true; } +#else + return false; +#endif } =20 /* Handle a CPU exception for A and R profile CPUs. --=20 2.20.1 From nobody Mon May 13 12:20:01 2024 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=1562019258; cv=none; d=zoho.com; s=zohoarc; b=VI7GvzvdLVzCTGIEITYnRB3pHkwhOSppmNPx3EQwd6E27MQXqWUldzwMW+p3PcSynBQgWi3a6Ds6oFQvDF2Fl0N5q6c8G5/dqiP5AE9VOyqHagNmpVryIX5QlrcoPH9XwTBNG12rdUlrBEytHn6kCJ7L/TbFMBbS9I457zJ3orA= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zoho.com; s=zohoarc; t=1562019258; h=Content-Type: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=pcqKoCWH244/1BnS1GrM93akmpXAwm4vyGEk8iXbL3o=; b=IrSjLcasfBjCogEGFILDEFtl9rK8qzu8pXW9TIyqwTmcgC8agcsC5TgZo81XaeKBycS4utUKx7fOfjdaOYl9TdPFuT0+D+oTBMr1fgvuG1hsHXrfimiAmaxKv85NV9aHp8fND/4XBKPweoVNBAQRUBOH8aaguSDBj41QZZc6b/s= 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 1562019258264941.4380242226583; Mon, 1 Jul 2019 15:14:18 -0700 (PDT) Received: from localhost ([::1]:45968 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.86_2) (envelope-from ) id 1hi4Yy-00046Q-UY for importer@patchew.org; Mon, 01 Jul 2019 18:14:16 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:56982) by lists.gnu.org with esmtp (Exim 4.86_2) (envelope-from ) id 1hi3Y9-0000K0-5i for qemu-devel@nongnu.org; Mon, 01 Jul 2019 17:09:32 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1hi3Xx-0006iQ-47 for qemu-devel@nongnu.org; Mon, 01 Jul 2019 17:09:21 -0400 Received: from mx1.redhat.com ([209.132.183.28]:56246) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1hi3XT-0006R9-LP; Mon, 01 Jul 2019 17:08:40 -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 B6067223862; Mon, 1 Jul 2019 19:50:06 +0000 (UTC) Received: from x1w.redhat.com (unknown [10.40.205.170]) by smtp.corp.redhat.com (Postfix) with ESMTPS id 7F4966C35B; Mon, 1 Jul 2019 19:50:00 +0000 (UTC) From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= To: qemu-devel@nongnu.org Date: Mon, 1 Jul 2019 21:49:37 +0200 Message-Id: <20190701194942.10092-4-philmd@redhat.com> In-Reply-To: <20190701194942.10092-1-philmd@redhat.com> References: <20190701194942.10092-1-philmd@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.39]); Mon, 01 Jul 2019 19:50:10 +0000 (UTC) Content-Transfer-Encoding: quoted-printable X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] X-Received-From: 209.132.183.28 Subject: [Qemu-devel] [PATCH v4 3/8] target/arm/helper: Move M profile routines to m_helper.c 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: Yang Zhong , Peter Maydell , Andrew Jones , Samuel Ortiz , Rob Bradford , =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= , Thomas Huth , qemu-arm@nongnu.org, Paolo Bonzini , =?UTF-8?q?Alex=20Benn=C3=A9e?= Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" Content-Type: text/plain; charset="utf-8" In preparation for supporting TCG disablement on ARM, we move most of TCG related v7m/v8m helpers and APIs into their own file. Note: It is easier to review this commit using the 'histogram' diff algorithm: $ git diff --diff-algorithm=3Dhistogram ... or $ git diff --histogram ... Suggested-by: Samuel Ortiz Signed-off-by: Philippe Mathieu-Daud=C3=A9 --- patch generated with git diff --histogram. v4: rebased --- target/arm/Makefile.objs | 1 + target/arm/helper.c | 2661 +------------------------------------ target/arm/m_helper.c | 2676 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 2681 insertions(+), 2657 deletions(-) create mode 100644 target/arm/m_helper.c diff --git a/target/arm/Makefile.objs b/target/arm/Makefile.objs index 82bedefc3d..89cd7c36e3 100644 --- a/target/arm/Makefile.objs +++ b/target/arm/Makefile.objs @@ -36,6 +36,7 @@ obj-y +=3D tlb_helper.o debug_helper.o obj-y +=3D translate.o op_helper.o obj-y +=3D crypto_helper.o obj-y +=3D iwmmxt_helper.o vec_helper.o neon_helper.o +obj-$(CONFIG_ARM_V7M) +=3D m_helper.o =20 obj-$(CONFIG_SOFTMMU) +=3D psci.o =20 diff --git a/target/arm/helper.c b/target/arm/helper.c index 6d91e0a1f9..7ce01f4398 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -19,7 +19,6 @@ #include "qemu/crc32c.h" #include "qemu/qemu-print.h" #include "exec/exec-all.h" -#include "exec/cpu_ldst.h" #include /* For crc32 */ #include "hw/semihosting/semihost.h" #include "sysemu/cpus.h" @@ -30,6 +29,7 @@ #include "qemu/guest-random.h" #ifdef CONFIG_TCG #include "arm_ldst.h" +#include "exec/cpu_ldst.h" #endif =20 #define ARM_CPU_FREQ 1000000000 /* FIXME: 1 GHz, should be configurable */ @@ -7457,75 +7457,6 @@ uint32_t HELPER(rbit)(uint32_t x) =20 #ifdef CONFIG_USER_ONLY =20 -/* These should probably raise undefined insn exceptions. */ -void HELPER(v7m_msr)(CPUARMState *env, uint32_t reg, uint32_t val) -{ - ARMCPU *cpu =3D env_archcpu(env); - - cpu_abort(CPU(cpu), "v7m_msr %d\n", reg); -} - -uint32_t HELPER(v7m_mrs)(CPUARMState *env, uint32_t reg) -{ - ARMCPU *cpu =3D env_archcpu(env); - - cpu_abort(CPU(cpu), "v7m_mrs %d\n", reg); - return 0; -} - -void HELPER(v7m_bxns)(CPUARMState *env, uint32_t dest) -{ - /* translate.c should never generate calls here in user-only mode */ - g_assert_not_reached(); -} - -void HELPER(v7m_blxns)(CPUARMState *env, uint32_t dest) -{ - /* translate.c should never generate calls here in user-only mode */ - g_assert_not_reached(); -} - -void HELPER(v7m_preserve_fp_state)(CPUARMState *env) -{ - /* translate.c should never generate calls here in user-only mode */ - g_assert_not_reached(); -} - -void HELPER(v7m_vlstm)(CPUARMState *env, uint32_t fptr) -{ - /* translate.c should never generate calls here in user-only mode */ - g_assert_not_reached(); -} - -void HELPER(v7m_vlldm)(CPUARMState *env, uint32_t fptr) -{ - /* translate.c should never generate calls here in user-only mode */ - g_assert_not_reached(); -} - -uint32_t HELPER(v7m_tt)(CPUARMState *env, uint32_t addr, uint32_t op) -{ - /* - * The TT instructions can be used by unprivileged code, but in - * user-only emulation we don't have the MPU. - * Luckily since we know we are NonSecure unprivileged (and that in - * turn means that the A flag wasn't specified), all the bits in the - * register must be zero: - * IREGION: 0 because IRVALID is 0 - * IRVALID: 0 because NS - * S: 0 because NS - * NSRW: 0 because NS - * NSR: 0 because NS - * RW: 0 because unpriv and A flag not set - * R: 0 because unpriv and A flag not set - * SRVALID: 0 because NS - * MRVALID: 0 because unpriv and A flag not set - * SREGION: 0 becaus SRVALID is 0 - * MREGION: 0 because MRVALID is 0 - */ - return 0; -} - static void switch_mode(CPUARMState *env, int mode) { ARMCPU *cpu =3D env_archcpu(env); @@ -7720,2078 +7651,6 @@ void arm_log_exception(int idx) } } =20 -/* - * What kind of stack write are we doing? This affects how exceptions - * generated during the stacking are treated. - */ -typedef enum StackingMode { - STACK_NORMAL, - STACK_IGNFAULTS, - STACK_LAZYFP, -} StackingMode; - -static bool v7m_stack_write(ARMCPU *cpu, uint32_t addr, uint32_t value, - ARMMMUIdx mmu_idx, StackingMode mode) -{ - CPUState *cs =3D CPU(cpu); - CPUARMState *env =3D &cpu->env; - MemTxAttrs attrs =3D {}; - MemTxResult txres; - target_ulong page_size; - hwaddr physaddr; - int prot; - ARMMMUFaultInfo fi =3D {}; - bool secure =3D mmu_idx & ARM_MMU_IDX_M_S; - int exc; - bool exc_secure; - - if (get_phys_addr(env, addr, MMU_DATA_STORE, mmu_idx, &physaddr, - &attrs, &prot, &page_size, &fi, NULL)) { - /* MPU/SAU lookup failed */ - if (fi.type =3D=3D ARMFault_QEMU_SFault) { - if (mode =3D=3D STACK_LAZYFP) { - qemu_log_mask(CPU_LOG_INT, - "...SecureFault with SFSR.LSPERR " - "during lazy stacking\n"); - env->v7m.sfsr |=3D R_V7M_SFSR_LSPERR_MASK; - } else { - qemu_log_mask(CPU_LOG_INT, - "...SecureFault with SFSR.AUVIOL " - "during stacking\n"); - env->v7m.sfsr |=3D R_V7M_SFSR_AUVIOL_MASK; - } - env->v7m.sfsr |=3D R_V7M_SFSR_SFARVALID_MASK; - env->v7m.sfar =3D addr; - exc =3D ARMV7M_EXCP_SECURE; - exc_secure =3D false; - } else { - if (mode =3D=3D STACK_LAZYFP) { - qemu_log_mask(CPU_LOG_INT, - "...MemManageFault with CFSR.MLSPERR\n"); - env->v7m.cfsr[secure] |=3D R_V7M_CFSR_MLSPERR_MASK; - } else { - qemu_log_mask(CPU_LOG_INT, - "...MemManageFault with CFSR.MSTKERR\n"); - env->v7m.cfsr[secure] |=3D R_V7M_CFSR_MSTKERR_MASK; - } - exc =3D ARMV7M_EXCP_MEM; - exc_secure =3D secure; - } - goto pend_fault; - } - address_space_stl_le(arm_addressspace(cs, attrs), physaddr, value, - attrs, &txres); - if (txres !=3D MEMTX_OK) { - /* BusFault trying to write the data */ - if (mode =3D=3D STACK_LAZYFP) { - qemu_log_mask(CPU_LOG_INT, "...BusFault with BFSR.LSPERR\n"); - env->v7m.cfsr[M_REG_NS] |=3D R_V7M_CFSR_LSPERR_MASK; - } else { - qemu_log_mask(CPU_LOG_INT, "...BusFault with BFSR.STKERR\n"); - env->v7m.cfsr[M_REG_NS] |=3D R_V7M_CFSR_STKERR_MASK; - } - exc =3D ARMV7M_EXCP_BUS; - exc_secure =3D false; - goto pend_fault; - } - return true; - -pend_fault: - /* - * By pending the exception at this point we are making - * the IMPDEF choice "overridden exceptions pended" (see the - * MergeExcInfo() pseudocode). The other choice would be to not - * pend them now and then make a choice about which to throw away - * later if we have two derived exceptions. - * The only case when we must not pend the exception but instead - * throw it away is if we are doing the push of the callee registers - * and we've already generated a derived exception (this is indicated - * by the caller passing STACK_IGNFAULTS). Even in this case we will - * still update the fault status registers. - */ - switch (mode) { - case STACK_NORMAL: - armv7m_nvic_set_pending_derived(env->nvic, exc, exc_secure); - break; - case STACK_LAZYFP: - armv7m_nvic_set_pending_lazyfp(env->nvic, exc, exc_secure); - break; - case STACK_IGNFAULTS: - break; - } - return false; -} - -static bool v7m_stack_read(ARMCPU *cpu, uint32_t *dest, uint32_t addr, - ARMMMUIdx mmu_idx) -{ - CPUState *cs =3D CPU(cpu); - CPUARMState *env =3D &cpu->env; - MemTxAttrs attrs =3D {}; - MemTxResult txres; - target_ulong page_size; - hwaddr physaddr; - int prot; - ARMMMUFaultInfo fi =3D {}; - bool secure =3D mmu_idx & ARM_MMU_IDX_M_S; - int exc; - bool exc_secure; - uint32_t value; - - if (get_phys_addr(env, addr, MMU_DATA_LOAD, mmu_idx, &physaddr, - &attrs, &prot, &page_size, &fi, NULL)) { - /* MPU/SAU lookup failed */ - if (fi.type =3D=3D ARMFault_QEMU_SFault) { - qemu_log_mask(CPU_LOG_INT, - "...SecureFault with SFSR.AUVIOL during unstack\= n"); - env->v7m.sfsr |=3D R_V7M_SFSR_AUVIOL_MASK | R_V7M_SFSR_SFARVAL= ID_MASK; - env->v7m.sfar =3D addr; - exc =3D ARMV7M_EXCP_SECURE; - exc_secure =3D false; - } else { - qemu_log_mask(CPU_LOG_INT, - "...MemManageFault with CFSR.MUNSTKERR\n"); - env->v7m.cfsr[secure] |=3D R_V7M_CFSR_MUNSTKERR_MASK; - exc =3D ARMV7M_EXCP_MEM; - exc_secure =3D secure; - } - goto pend_fault; - } - - value =3D address_space_ldl(arm_addressspace(cs, attrs), physaddr, - attrs, &txres); - if (txres !=3D MEMTX_OK) { - /* BusFault trying to read the data */ - qemu_log_mask(CPU_LOG_INT, "...BusFault with BFSR.UNSTKERR\n"); - env->v7m.cfsr[M_REG_NS] |=3D R_V7M_CFSR_UNSTKERR_MASK; - exc =3D ARMV7M_EXCP_BUS; - exc_secure =3D false; - goto pend_fault; - } - - *dest =3D value; - return true; - -pend_fault: - /* - * By pending the exception at this point we are making - * the IMPDEF choice "overridden exceptions pended" (see the - * MergeExcInfo() pseudocode). The other choice would be to not - * pend them now and then make a choice about which to throw away - * later if we have two derived exceptions. - */ - armv7m_nvic_set_pending(env->nvic, exc, exc_secure); - return false; -} - -void HELPER(v7m_preserve_fp_state)(CPUARMState *env) -{ - /* - * Preserve FP state (because LSPACT was set and we are about - * to execute an FP instruction). This corresponds to the - * PreserveFPState() pseudocode. - * We may throw an exception if the stacking fails. - */ - ARMCPU *cpu =3D env_archcpu(env); - bool is_secure =3D env->v7m.fpccr[M_REG_S] & R_V7M_FPCCR_S_MASK; - bool negpri =3D !(env->v7m.fpccr[M_REG_S] & R_V7M_FPCCR_HFRDY_MASK); - bool is_priv =3D !(env->v7m.fpccr[is_secure] & R_V7M_FPCCR_USER_MASK); - bool splimviol =3D env->v7m.fpccr[is_secure] & R_V7M_FPCCR_SPLIMVIOL_M= ASK; - uint32_t fpcar =3D env->v7m.fpcar[is_secure]; - bool stacked_ok =3D true; - bool ts =3D is_secure && (env->v7m.fpccr[M_REG_S] & R_V7M_FPCCR_TS_MAS= K); - bool take_exception; - - /* Take the iothread lock as we are going to touch the NVIC */ - qemu_mutex_lock_iothread(); - - /* Check the background context had access to the FPU */ - if (!v7m_cpacr_pass(env, is_secure, is_priv)) { - armv7m_nvic_set_pending_lazyfp(env->nvic, ARMV7M_EXCP_USAGE, is_se= cure); - env->v7m.cfsr[is_secure] |=3D R_V7M_CFSR_NOCP_MASK; - stacked_ok =3D false; - } else if (!is_secure && !extract32(env->v7m.nsacr, 10, 1)) { - armv7m_nvic_set_pending_lazyfp(env->nvic, ARMV7M_EXCP_USAGE, M_REG= _S); - env->v7m.cfsr[M_REG_S] |=3D R_V7M_CFSR_NOCP_MASK; - stacked_ok =3D false; - } - - if (!splimviol && stacked_ok) { - /* We only stack if the stack limit wasn't violated */ - int i; - ARMMMUIdx mmu_idx; - - mmu_idx =3D arm_v7m_mmu_idx_all(env, is_secure, is_priv, negpri); - for (i =3D 0; i < (ts ? 32 : 16); i +=3D 2) { - uint64_t dn =3D *aa32_vfp_dreg(env, i / 2); - uint32_t faddr =3D fpcar + 4 * i; - uint32_t slo =3D extract64(dn, 0, 32); - uint32_t shi =3D extract64(dn, 32, 32); - - if (i >=3D 16) { - faddr +=3D 8; /* skip the slot for the FPSCR */ - } - stacked_ok =3D stacked_ok && - v7m_stack_write(cpu, faddr, slo, mmu_idx, STACK_LAZYFP) && - v7m_stack_write(cpu, faddr + 4, shi, mmu_idx, STACK_LAZYFP= ); - } - - stacked_ok =3D stacked_ok && - v7m_stack_write(cpu, fpcar + 0x40, - vfp_get_fpscr(env), mmu_idx, STACK_LAZYFP); - } - - /* - * We definitely pended an exception, but it's possible that it - * might not be able to be taken now. If its priority permits us - * to take it now, then we must not update the LSPACT or FP regs, - * but instead jump out to take the exception immediately. - * If it's just pending and won't be taken until the current - * handler exits, then we do update LSPACT and the FP regs. - */ - take_exception =3D !stacked_ok && - armv7m_nvic_can_take_pending_exception(env->nvic); - - qemu_mutex_unlock_iothread(); - - if (take_exception) { - raise_exception_ra(env, EXCP_LAZYFP, 0, 1, GETPC()); - } - - env->v7m.fpccr[is_secure] &=3D ~R_V7M_FPCCR_LSPACT_MASK; - - if (ts) { - /* Clear s0 to s31 and the FPSCR */ - int i; - - for (i =3D 0; i < 32; i +=3D 2) { - *aa32_vfp_dreg(env, i / 2) =3D 0; - } - vfp_set_fpscr(env, 0); - } - /* - * Otherwise s0 to s15 and FPSCR are UNKNOWN; we choose to leave them - * unchanged. - */ -} - -/* - * Write to v7M CONTROL.SPSEL bit for the specified security bank. - * This may change the current stack pointer between Main and Process - * stack pointers if it is done for the CONTROL register for the current - * security state. - */ -static void write_v7m_control_spsel_for_secstate(CPUARMState *env, - bool new_spsel, - bool secstate) -{ - bool old_is_psp =3D v7m_using_psp(env); - - env->v7m.control[secstate] =3D - deposit32(env->v7m.control[secstate], - R_V7M_CONTROL_SPSEL_SHIFT, - R_V7M_CONTROL_SPSEL_LENGTH, new_spsel); - - if (secstate =3D=3D env->v7m.secure) { - bool new_is_psp =3D v7m_using_psp(env); - uint32_t tmp; - - if (old_is_psp !=3D new_is_psp) { - tmp =3D env->v7m.other_sp; - env->v7m.other_sp =3D env->regs[13]; - env->regs[13] =3D tmp; - } - } -} - -/* - * Write to v7M CONTROL.SPSEL bit. This may change the current - * stack pointer between Main and Process stack pointers. - */ -static void write_v7m_control_spsel(CPUARMState *env, bool new_spsel) -{ - write_v7m_control_spsel_for_secstate(env, new_spsel, env->v7m.secure); -} - -void write_v7m_exception(CPUARMState *env, uint32_t new_exc) -{ - /* - * Write a new value to v7m.exception, thus transitioning into or out - * of Handler mode; this may result in a change of active stack pointe= r. - */ - bool new_is_psp, old_is_psp =3D v7m_using_psp(env); - uint32_t tmp; - - env->v7m.exception =3D new_exc; - - new_is_psp =3D v7m_using_psp(env); - - if (old_is_psp !=3D new_is_psp) { - tmp =3D env->v7m.other_sp; - env->v7m.other_sp =3D env->regs[13]; - env->regs[13] =3D tmp; - } -} - -/* Switch M profile security state between NS and S */ -static void switch_v7m_security_state(CPUARMState *env, bool new_secstate) -{ - uint32_t new_ss_msp, new_ss_psp; - - if (env->v7m.secure =3D=3D new_secstate) { - return; - } - - /* - * All the banked state is accessed by looking at env->v7m.secure - * except for the stack pointer; rearrange the SP appropriately. - */ - new_ss_msp =3D env->v7m.other_ss_msp; - new_ss_psp =3D env->v7m.other_ss_psp; - - if (v7m_using_psp(env)) { - env->v7m.other_ss_psp =3D env->regs[13]; - env->v7m.other_ss_msp =3D env->v7m.other_sp; - } else { - env->v7m.other_ss_msp =3D env->regs[13]; - env->v7m.other_ss_psp =3D env->v7m.other_sp; - } - - env->v7m.secure =3D new_secstate; - - if (v7m_using_psp(env)) { - env->regs[13] =3D new_ss_psp; - env->v7m.other_sp =3D new_ss_msp; - } else { - env->regs[13] =3D new_ss_msp; - env->v7m.other_sp =3D new_ss_psp; - } -} - -void HELPER(v7m_bxns)(CPUARMState *env, uint32_t dest) -{ - /* - * Handle v7M BXNS: - * - if the return value is a magic value, do exception return (like = BX) - * - otherwise bit 0 of the return value is the target security state - */ - uint32_t min_magic; - - if (arm_feature(env, ARM_FEATURE_M_SECURITY)) { - /* Covers FNC_RETURN and EXC_RETURN magic */ - min_magic =3D FNC_RETURN_MIN_MAGIC; - } else { - /* EXC_RETURN magic only */ - min_magic =3D EXC_RETURN_MIN_MAGIC; - } - - if (dest >=3D min_magic) { - /* - * This is an exception return magic value; put it where - * do_v7m_exception_exit() expects and raise EXCEPTION_EXIT. - * Note that if we ever add gen_ss_advance() singlestep support to - * M profile this should count as an "instruction execution comple= te" - * event (compare gen_bx_excret_final_code()). - */ - env->regs[15] =3D dest & ~1; - env->thumb =3D dest & 1; - HELPER(exception_internal)(env, EXCP_EXCEPTION_EXIT); - /* notreached */ - } - - /* translate.c should have made BXNS UNDEF unless we're secure */ - assert(env->v7m.secure); - - if (!(dest & 1)) { - env->v7m.control[M_REG_S] &=3D ~R_V7M_CONTROL_SFPA_MASK; - } - switch_v7m_security_state(env, dest & 1); - env->thumb =3D 1; - env->regs[15] =3D dest & ~1; -} - -void HELPER(v7m_blxns)(CPUARMState *env, uint32_t dest) -{ - /* - * Handle v7M BLXNS: - * - bit 0 of the destination address is the target security state - */ - - /* At this point regs[15] is the address just after the BLXNS */ - uint32_t nextinst =3D env->regs[15] | 1; - uint32_t sp =3D env->regs[13] - 8; - uint32_t saved_psr; - - /* translate.c will have made BLXNS UNDEF unless we're secure */ - assert(env->v7m.secure); - - if (dest & 1) { - /* - * Target is Secure, so this is just a normal BLX, - * except that the low bit doesn't indicate Thumb/not. - */ - env->regs[14] =3D nextinst; - env->thumb =3D 1; - env->regs[15] =3D dest & ~1; - return; - } - - /* Target is non-secure: first push a stack frame */ - if (!QEMU_IS_ALIGNED(sp, 8)) { - qemu_log_mask(LOG_GUEST_ERROR, - "BLXNS with misaligned SP is UNPREDICTABLE\n"); - } - - if (sp < v7m_sp_limit(env)) { - raise_exception(env, EXCP_STKOF, 0, 1); - } - - saved_psr =3D env->v7m.exception; - if (env->v7m.control[M_REG_S] & R_V7M_CONTROL_SFPA_MASK) { - saved_psr |=3D XPSR_SFPA; - } - - /* Note that these stores can throw exceptions on MPU faults */ - cpu_stl_data(env, sp, nextinst); - cpu_stl_data(env, sp + 4, saved_psr); - - env->regs[13] =3D sp; - env->regs[14] =3D 0xfeffffff; - if (arm_v7m_is_handler_mode(env)) { - /* - * Write a dummy value to IPSR, to avoid leaking the current secure - * exception number to non-secure code. This is guaranteed not - * to cause write_v7m_exception() to actually change stacks. - */ - write_v7m_exception(env, 1); - } - env->v7m.control[M_REG_S] &=3D ~R_V7M_CONTROL_SFPA_MASK; - switch_v7m_security_state(env, 0); - env->thumb =3D 1; - env->regs[15] =3D dest; -} - -static uint32_t *get_v7m_sp_ptr(CPUARMState *env, bool secure, bool thread= mode, - bool spsel) -{ - /* - * Return a pointer to the location where we currently store the - * stack pointer for the requested security state and thread mode. - * This pointer will become invalid if the CPU state is updated - * such that the stack pointers are switched around (eg changing - * the SPSEL control bit). - * Compare the v8M ARM ARM pseudocode LookUpSP_with_security_mode(). - * Unlike that pseudocode, we require the caller to pass us in the - * SPSEL control bit value; this is because we also use this - * function in handling of pushing of the callee-saves registers - * part of the v8M stack frame (pseudocode PushCalleeStack()), - * and in the tailchain codepath the SPSEL bit comes from the exception - * return magic LR value from the previous exception. The pseudocode - * opencodes the stack-selection in PushCalleeStack(), but we prefer - * to make this utility function generic enough to do the job. - */ - bool want_psp =3D threadmode && spsel; - - if (secure =3D=3D env->v7m.secure) { - if (want_psp =3D=3D v7m_using_psp(env)) { - return &env->regs[13]; - } else { - return &env->v7m.other_sp; - } - } else { - if (want_psp) { - return &env->v7m.other_ss_psp; - } else { - return &env->v7m.other_ss_msp; - } - } -} - -static bool arm_v7m_load_vector(ARMCPU *cpu, int exc, bool targets_secure, - uint32_t *pvec) -{ - CPUState *cs =3D CPU(cpu); - CPUARMState *env =3D &cpu->env; - MemTxResult result; - uint32_t addr =3D env->v7m.vecbase[targets_secure] + exc * 4; - uint32_t vector_entry; - MemTxAttrs attrs =3D {}; - ARMMMUIdx mmu_idx; - bool exc_secure; - - mmu_idx =3D arm_v7m_mmu_idx_for_secstate_and_priv(env, targets_secure,= true); - - /* - * We don't do a get_phys_addr() here because the rules for vector - * loads are special: they always use the default memory map, and - * the default memory map permits reads from all addresses. - * Since there's no easy way to pass through to pmsav8_mpu_lookup() - * that we want this special case which would always say "yes", - * we just do the SAU lookup here followed by a direct physical load. - */ - attrs.secure =3D targets_secure; - attrs.user =3D false; - - if (arm_feature(env, ARM_FEATURE_M_SECURITY)) { - V8M_SAttributes sattrs =3D {}; - - v8m_security_lookup(env, addr, MMU_DATA_LOAD, mmu_idx, &sattrs); - if (sattrs.ns) { - attrs.secure =3D false; - } else if (!targets_secure) { - /* NS access to S memory */ - goto load_fail; - } - } - - vector_entry =3D address_space_ldl(arm_addressspace(cs, attrs), addr, - attrs, &result); - if (result !=3D MEMTX_OK) { - goto load_fail; - } - *pvec =3D vector_entry; - return true; - -load_fail: - /* - * All vector table fetch fails are reported as HardFault, with - * HFSR.VECTTBL and .FORCED set. (FORCED is set because - * technically the underlying exception is a MemManage or BusFault - * that is escalated to HardFault.) This is a terminal exception, - * so we will either take the HardFault immediately or else enter - * lockup (the latter case is handled in armv7m_nvic_set_pending_deriv= ed()). - */ - exc_secure =3D targets_secure || - !(cpu->env.v7m.aircr & R_V7M_AIRCR_BFHFNMINS_MASK); - env->v7m.hfsr |=3D R_V7M_HFSR_VECTTBL_MASK | R_V7M_HFSR_FORCED_MASK; - armv7m_nvic_set_pending_derived(env->nvic, ARMV7M_EXCP_HARD, exc_secur= e); - return false; -} - -static uint32_t v7m_integrity_sig(CPUARMState *env, uint32_t lr) -{ - /* - * Return the integrity signature value for the callee-saves - * stack frame section. @lr is the exception return payload/LR value - * whose FType bit forms bit 0 of the signature if FP is present. - */ - uint32_t sig =3D 0xfefa125a; - - if (!arm_feature(env, ARM_FEATURE_VFP) || (lr & R_V7M_EXCRET_FTYPE_MAS= K)) { - sig |=3D 1; - } - return sig; -} - -static bool v7m_push_callee_stack(ARMCPU *cpu, uint32_t lr, bool dotailcha= in, - bool ignore_faults) -{ - /* - * For v8M, push the callee-saves register part of the stack frame. - * Compare the v8M pseudocode PushCalleeStack(). - * In the tailchaining case this may not be the current stack. - */ - CPUARMState *env =3D &cpu->env; - uint32_t *frame_sp_p; - uint32_t frameptr; - ARMMMUIdx mmu_idx; - bool stacked_ok; - uint32_t limit; - bool want_psp; - uint32_t sig; - StackingMode smode =3D ignore_faults ? STACK_IGNFAULTS : STACK_NORMAL; - - if (dotailchain) { - bool mode =3D lr & R_V7M_EXCRET_MODE_MASK; - bool priv =3D !(env->v7m.control[M_REG_S] & R_V7M_CONTROL_NPRIV_MA= SK) || - !mode; - - mmu_idx =3D arm_v7m_mmu_idx_for_secstate_and_priv(env, M_REG_S, pr= iv); - frame_sp_p =3D get_v7m_sp_ptr(env, M_REG_S, mode, - lr & R_V7M_EXCRET_SPSEL_MASK); - want_psp =3D mode && (lr & R_V7M_EXCRET_SPSEL_MASK); - if (want_psp) { - limit =3D env->v7m.psplim[M_REG_S]; - } else { - limit =3D env->v7m.msplim[M_REG_S]; - } - } else { - mmu_idx =3D arm_mmu_idx(env); - frame_sp_p =3D &env->regs[13]; - limit =3D v7m_sp_limit(env); - } - - frameptr =3D *frame_sp_p - 0x28; - if (frameptr < limit) { - /* - * Stack limit failure: set SP to the limit value, and generate - * STKOF UsageFault. Stack pushes below the limit must not be - * performed. It is IMPDEF whether pushes above the limit are - * performed; we choose not to. - */ - qemu_log_mask(CPU_LOG_INT, - "...STKOF during callee-saves register stacking\n"); - env->v7m.cfsr[env->v7m.secure] |=3D R_V7M_CFSR_STKOF_MASK; - armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_USAGE, - env->v7m.secure); - *frame_sp_p =3D limit; - return true; - } - - /* - * Write as much of the stack frame as we can. A write failure may - * cause us to pend a derived exception. - */ - sig =3D v7m_integrity_sig(env, lr); - stacked_ok =3D - v7m_stack_write(cpu, frameptr, sig, mmu_idx, smode) && - v7m_stack_write(cpu, frameptr + 0x8, env->regs[4], mmu_idx, smode)= && - v7m_stack_write(cpu, frameptr + 0xc, env->regs[5], mmu_idx, smode)= && - v7m_stack_write(cpu, frameptr + 0x10, env->regs[6], mmu_idx, smode= ) && - v7m_stack_write(cpu, frameptr + 0x14, env->regs[7], mmu_idx, smode= ) && - v7m_stack_write(cpu, frameptr + 0x18, env->regs[8], mmu_idx, smode= ) && - v7m_stack_write(cpu, frameptr + 0x1c, env->regs[9], mmu_idx, smode= ) && - v7m_stack_write(cpu, frameptr + 0x20, env->regs[10], mmu_idx, smod= e) && - v7m_stack_write(cpu, frameptr + 0x24, env->regs[11], mmu_idx, smod= e); - - /* Update SP regardless of whether any of the stack accesses failed. */ - *frame_sp_p =3D frameptr; - - return !stacked_ok; -} - -static void v7m_exception_taken(ARMCPU *cpu, uint32_t lr, bool dotailchain, - bool ignore_stackfaults) -{ - /* - * Do the "take the exception" parts of exception entry, - * but not the pushing of state to the stack. This is - * similar to the pseudocode ExceptionTaken() function. - */ - CPUARMState *env =3D &cpu->env; - uint32_t addr; - bool targets_secure; - int exc; - bool push_failed =3D false; - - armv7m_nvic_get_pending_irq_info(env->nvic, &exc, &targets_secure); - qemu_log_mask(CPU_LOG_INT, "...taking pending %s exception %d\n", - targets_secure ? "secure" : "nonsecure", exc); - - if (dotailchain) { - /* Sanitize LR FType and PREFIX bits */ - if (!arm_feature(env, ARM_FEATURE_VFP)) { - lr |=3D R_V7M_EXCRET_FTYPE_MASK; - } - lr =3D deposit32(lr, 24, 8, 0xff); - } - - if (arm_feature(env, ARM_FEATURE_V8)) { - if (arm_feature(env, ARM_FEATURE_M_SECURITY) && - (lr & R_V7M_EXCRET_S_MASK)) { - /* - * The background code (the owner of the registers in the - * exception frame) is Secure. This means it may either already - * have or now needs to push callee-saves registers. - */ - if (targets_secure) { - if (dotailchain && !(lr & R_V7M_EXCRET_ES_MASK)) { - /* - * We took an exception from Secure to NonSecure - * (which means the callee-saved registers got stacked) - * and are now tailchaining to a Secure exception. - * Clear DCRS so eventual return from this Secure - * exception unstacks the callee-saved registers. - */ - lr &=3D ~R_V7M_EXCRET_DCRS_MASK; - } - } else { - /* - * We're going to a non-secure exception; push the - * callee-saves registers to the stack now, if they're - * not already saved. - */ - if (lr & R_V7M_EXCRET_DCRS_MASK && - !(dotailchain && !(lr & R_V7M_EXCRET_ES_MASK))) { - push_failed =3D v7m_push_callee_stack(cpu, lr, dotailc= hain, - ignore_stackfaults= ); - } - lr |=3D R_V7M_EXCRET_DCRS_MASK; - } - } - - lr &=3D ~R_V7M_EXCRET_ES_MASK; - if (targets_secure || !arm_feature(env, ARM_FEATURE_M_SECURITY)) { - lr |=3D R_V7M_EXCRET_ES_MASK; - } - lr &=3D ~R_V7M_EXCRET_SPSEL_MASK; - if (env->v7m.control[targets_secure] & R_V7M_CONTROL_SPSEL_MASK) { - lr |=3D R_V7M_EXCRET_SPSEL_MASK; - } - - /* - * Clear registers if necessary to prevent non-secure exception - * code being able to see register values from secure code. - * Where register values become architecturally UNKNOWN we leave - * them with their previous values. - */ - if (arm_feature(env, ARM_FEATURE_M_SECURITY)) { - if (!targets_secure) { - /* - * Always clear the caller-saved registers (they have been - * pushed to the stack earlier in v7m_push_stack()). - * Clear callee-saved registers if the background code is - * Secure (in which case these regs were saved in - * v7m_push_callee_stack()). - */ - int i; - - for (i =3D 0; i < 13; i++) { - /* r4..r11 are callee-saves, zero only if EXCRET.S =3D= =3D 1 */ - if (i < 4 || i > 11 || (lr & R_V7M_EXCRET_S_MASK)) { - env->regs[i] =3D 0; - } - } - /* Clear EAPSR */ - xpsr_write(env, 0, XPSR_NZCV | XPSR_Q | XPSR_GE | XPSR_IT); - } - } - } - - if (push_failed && !ignore_stackfaults) { - /* - * Derived exception on callee-saves register stacking: - * we might now want to take a different exception which - * targets a different security state, so try again from the top. - */ - qemu_log_mask(CPU_LOG_INT, - "...derived exception on callee-saves register stack= ing"); - v7m_exception_taken(cpu, lr, true, true); - return; - } - - if (!arm_v7m_load_vector(cpu, exc, targets_secure, &addr)) { - /* Vector load failed: derived exception */ - qemu_log_mask(CPU_LOG_INT, "...derived exception on vector table l= oad"); - v7m_exception_taken(cpu, lr, true, true); - return; - } - - /* - * Now we've done everything that might cause a derived exception - * we can go ahead and activate whichever exception we're going to - * take (which might now be the derived exception). - */ - armv7m_nvic_acknowledge_irq(env->nvic); - - /* Switch to target security state -- must do this before writing SPSE= L */ - switch_v7m_security_state(env, targets_secure); - write_v7m_control_spsel(env, 0); - arm_clear_exclusive(env); - /* Clear SFPA and FPCA (has no effect if no FPU) */ - env->v7m.control[M_REG_S] &=3D - ~(R_V7M_CONTROL_FPCA_MASK | R_V7M_CONTROL_SFPA_MASK); - /* Clear IT bits */ - env->condexec_bits =3D 0; - env->regs[14] =3D lr; - env->regs[15] =3D addr & 0xfffffffe; - env->thumb =3D addr & 1; -} - -static void v7m_update_fpccr(CPUARMState *env, uint32_t frameptr, - bool apply_splim) -{ - /* - * Like the pseudocode UpdateFPCCR: save state in FPCAR and FPCCR - * that we will need later in order to do lazy FP reg stacking. - */ - bool is_secure =3D env->v7m.secure; - void *nvic =3D env->nvic; - /* - * Some bits are unbanked and live always in fpccr[M_REG_S]; some bits - * are banked and we want to update the bit in the bank for the - * current security state; and in one case we want to specifically - * update the NS banked version of a bit even if we are secure. - */ - uint32_t *fpccr_s =3D &env->v7m.fpccr[M_REG_S]; - uint32_t *fpccr_ns =3D &env->v7m.fpccr[M_REG_NS]; - uint32_t *fpccr =3D &env->v7m.fpccr[is_secure]; - bool hfrdy, bfrdy, mmrdy, ns_ufrdy, s_ufrdy, sfrdy, monrdy; - - env->v7m.fpcar[is_secure] =3D frameptr & ~0x7; - - if (apply_splim && arm_feature(env, ARM_FEATURE_V8)) { - bool splimviol; - uint32_t splim =3D v7m_sp_limit(env); - bool ign =3D armv7m_nvic_neg_prio_requested(nvic, is_secure) && - (env->v7m.ccr[is_secure] & R_V7M_CCR_STKOFHFNMIGN_MASK); - - splimviol =3D !ign && frameptr < splim; - *fpccr =3D FIELD_DP32(*fpccr, V7M_FPCCR, SPLIMVIOL, splimviol); - } - - *fpccr =3D FIELD_DP32(*fpccr, V7M_FPCCR, LSPACT, 1); - - *fpccr_s =3D FIELD_DP32(*fpccr_s, V7M_FPCCR, S, is_secure); - - *fpccr =3D FIELD_DP32(*fpccr, V7M_FPCCR, USER, arm_current_el(env) =3D= =3D 0); - - *fpccr =3D FIELD_DP32(*fpccr, V7M_FPCCR, THREAD, - !arm_v7m_is_handler_mode(env)); - - hfrdy =3D armv7m_nvic_get_ready_status(nvic, ARMV7M_EXCP_HARD, false); - *fpccr_s =3D FIELD_DP32(*fpccr_s, V7M_FPCCR, HFRDY, hfrdy); - - bfrdy =3D armv7m_nvic_get_ready_status(nvic, ARMV7M_EXCP_BUS, false); - *fpccr_s =3D FIELD_DP32(*fpccr_s, V7M_FPCCR, BFRDY, bfrdy); - - mmrdy =3D armv7m_nvic_get_ready_status(nvic, ARMV7M_EXCP_MEM, is_secur= e); - *fpccr =3D FIELD_DP32(*fpccr, V7M_FPCCR, MMRDY, mmrdy); - - ns_ufrdy =3D armv7m_nvic_get_ready_status(nvic, ARMV7M_EXCP_USAGE, fal= se); - *fpccr_ns =3D FIELD_DP32(*fpccr_ns, V7M_FPCCR, UFRDY, ns_ufrdy); - - monrdy =3D armv7m_nvic_get_ready_status(nvic, ARMV7M_EXCP_DEBUG, false= ); - *fpccr_s =3D FIELD_DP32(*fpccr_s, V7M_FPCCR, MONRDY, monrdy); - - if (arm_feature(env, ARM_FEATURE_M_SECURITY)) { - s_ufrdy =3D armv7m_nvic_get_ready_status(nvic, ARMV7M_EXCP_USAGE, = true); - *fpccr_s =3D FIELD_DP32(*fpccr_s, V7M_FPCCR, UFRDY, s_ufrdy); - - sfrdy =3D armv7m_nvic_get_ready_status(nvic, ARMV7M_EXCP_SECURE, f= alse); - *fpccr_s =3D FIELD_DP32(*fpccr_s, V7M_FPCCR, SFRDY, sfrdy); - } -} - -void HELPER(v7m_vlstm)(CPUARMState *env, uint32_t fptr) -{ - /* fptr is the value of Rn, the frame pointer we store the FP regs to = */ - bool s =3D env->v7m.fpccr[M_REG_S] & R_V7M_FPCCR_S_MASK; - bool lspact =3D env->v7m.fpccr[s] & R_V7M_FPCCR_LSPACT_MASK; - - assert(env->v7m.secure); - - if (!(env->v7m.control[M_REG_S] & R_V7M_CONTROL_SFPA_MASK)) { - return; - } - - /* Check access to the coprocessor is permitted */ - if (!v7m_cpacr_pass(env, true, arm_current_el(env) !=3D 0)) { - raise_exception_ra(env, EXCP_NOCP, 0, 1, GETPC()); - } - - if (lspact) { - /* LSPACT should not be active when there is active FP state */ - raise_exception_ra(env, EXCP_LSERR, 0, 1, GETPC()); - } - - if (fptr & 7) { - raise_exception_ra(env, EXCP_UNALIGNED, 0, 1, GETPC()); - } - - /* - * Note that we do not use v7m_stack_write() here, because the - * accesses should not set the FSR bits for stacking errors if they - * fail. (In pseudocode terms, they are AccType_NORMAL, not AccType_ST= ACK - * or AccType_LAZYFP). Faults in cpu_stl_data() will throw exceptions - * and longjmp out. - */ - if (!(env->v7m.fpccr[M_REG_S] & R_V7M_FPCCR_LSPEN_MASK)) { - bool ts =3D env->v7m.fpccr[M_REG_S] & R_V7M_FPCCR_TS_MASK; - int i; - - for (i =3D 0; i < (ts ? 32 : 16); i +=3D 2) { - uint64_t dn =3D *aa32_vfp_dreg(env, i / 2); - uint32_t faddr =3D fptr + 4 * i; - uint32_t slo =3D extract64(dn, 0, 32); - uint32_t shi =3D extract64(dn, 32, 32); - - if (i >=3D 16) { - faddr +=3D 8; /* skip the slot for the FPSCR */ - } - cpu_stl_data(env, faddr, slo); - cpu_stl_data(env, faddr + 4, shi); - } - cpu_stl_data(env, fptr + 0x40, vfp_get_fpscr(env)); - - /* - * If TS is 0 then s0 to s15 and FPSCR are UNKNOWN; we choose to - * leave them unchanged, matching our choice in v7m_preserve_fp_st= ate. - */ - if (ts) { - for (i =3D 0; i < 32; i +=3D 2) { - *aa32_vfp_dreg(env, i / 2) =3D 0; - } - vfp_set_fpscr(env, 0); - } - } else { - v7m_update_fpccr(env, fptr, false); - } - - env->v7m.control[M_REG_S] &=3D ~R_V7M_CONTROL_FPCA_MASK; -} - -void HELPER(v7m_vlldm)(CPUARMState *env, uint32_t fptr) -{ - /* fptr is the value of Rn, the frame pointer we load the FP regs from= */ - assert(env->v7m.secure); - - if (!(env->v7m.control[M_REG_S] & R_V7M_CONTROL_SFPA_MASK)) { - return; - } - - /* Check access to the coprocessor is permitted */ - if (!v7m_cpacr_pass(env, true, arm_current_el(env) !=3D 0)) { - raise_exception_ra(env, EXCP_NOCP, 0, 1, GETPC()); - } - - if (env->v7m.fpccr[M_REG_S] & R_V7M_FPCCR_LSPACT_MASK) { - /* State in FP is still valid */ - env->v7m.fpccr[M_REG_S] &=3D ~R_V7M_FPCCR_LSPACT_MASK; - } else { - bool ts =3D env->v7m.fpccr[M_REG_S] & R_V7M_FPCCR_TS_MASK; - int i; - uint32_t fpscr; - - if (fptr & 7) { - raise_exception_ra(env, EXCP_UNALIGNED, 0, 1, GETPC()); - } - - for (i =3D 0; i < (ts ? 32 : 16); i +=3D 2) { - uint32_t slo, shi; - uint64_t dn; - uint32_t faddr =3D fptr + 4 * i; - - if (i >=3D 16) { - faddr +=3D 8; /* skip the slot for the FPSCR */ - } - - slo =3D cpu_ldl_data(env, faddr); - shi =3D cpu_ldl_data(env, faddr + 4); - - dn =3D (uint64_t) shi << 32 | slo; - *aa32_vfp_dreg(env, i / 2) =3D dn; - } - fpscr =3D cpu_ldl_data(env, fptr + 0x40); - vfp_set_fpscr(env, fpscr); - } - - env->v7m.control[M_REG_S] |=3D R_V7M_CONTROL_FPCA_MASK; -} - -static bool v7m_push_stack(ARMCPU *cpu) -{ - /* - * Do the "set up stack frame" part of exception entry, - * similar to pseudocode PushStack(). - * Return true if we generate a derived exception (and so - * should ignore further stack faults trying to process - * that derived exception.) - */ - bool stacked_ok =3D true, limitviol =3D false; - CPUARMState *env =3D &cpu->env; - uint32_t xpsr =3D xpsr_read(env); - uint32_t frameptr =3D env->regs[13]; - ARMMMUIdx mmu_idx =3D arm_mmu_idx(env); - uint32_t framesize; - bool nsacr_cp10 =3D extract32(env->v7m.nsacr, 10, 1); - - if ((env->v7m.control[M_REG_S] & R_V7M_CONTROL_FPCA_MASK) && - (env->v7m.secure || nsacr_cp10)) { - if (env->v7m.secure && - env->v7m.fpccr[M_REG_S] & R_V7M_FPCCR_TS_MASK) { - framesize =3D 0xa8; - } else { - framesize =3D 0x68; - } - } else { - framesize =3D 0x20; - } - - /* Align stack pointer if the guest wants that */ - if ((frameptr & 4) && - (env->v7m.ccr[env->v7m.secure] & R_V7M_CCR_STKALIGN_MASK)) { - frameptr -=3D 4; - xpsr |=3D XPSR_SPREALIGN; - } - - xpsr &=3D ~XPSR_SFPA; - if (env->v7m.secure && - (env->v7m.control[M_REG_S] & R_V7M_CONTROL_SFPA_MASK)) { - xpsr |=3D XPSR_SFPA; - } - - frameptr -=3D framesize; - - if (arm_feature(env, ARM_FEATURE_V8)) { - uint32_t limit =3D v7m_sp_limit(env); - - if (frameptr < limit) { - /* - * Stack limit failure: set SP to the limit value, and generate - * STKOF UsageFault. Stack pushes below the limit must not be - * performed. It is IMPDEF whether pushes above the limit are - * performed; we choose not to. - */ - qemu_log_mask(CPU_LOG_INT, - "...STKOF during stacking\n"); - env->v7m.cfsr[env->v7m.secure] |=3D R_V7M_CFSR_STKOF_MASK; - armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_USAGE, - env->v7m.secure); - env->regs[13] =3D limit; - /* - * We won't try to perform any further memory accesses but - * we must continue through the following code to check for - * permission faults during FPU state preservation, and we - * must update FPCCR if lazy stacking is enabled. - */ - limitviol =3D true; - stacked_ok =3D false; - } - } - - /* - * Write as much of the stack frame as we can. If we fail a stack - * write this will result in a derived exception being pended - * (which may be taken in preference to the one we started with - * if it has higher priority). - */ - stacked_ok =3D stacked_ok && - v7m_stack_write(cpu, frameptr, env->regs[0], mmu_idx, STACK_NORMAL= ) && - v7m_stack_write(cpu, frameptr + 4, env->regs[1], - mmu_idx, STACK_NORMAL) && - v7m_stack_write(cpu, frameptr + 8, env->regs[2], - mmu_idx, STACK_NORMAL) && - v7m_stack_write(cpu, frameptr + 12, env->regs[3], - mmu_idx, STACK_NORMAL) && - v7m_stack_write(cpu, frameptr + 16, env->regs[12], - mmu_idx, STACK_NORMAL) && - v7m_stack_write(cpu, frameptr + 20, env->regs[14], - mmu_idx, STACK_NORMAL) && - v7m_stack_write(cpu, frameptr + 24, env->regs[15], - mmu_idx, STACK_NORMAL) && - v7m_stack_write(cpu, frameptr + 28, xpsr, mmu_idx, STACK_NORMAL); - - if (env->v7m.control[M_REG_S] & R_V7M_CONTROL_FPCA_MASK) { - /* FPU is active, try to save its registers */ - bool fpccr_s =3D env->v7m.fpccr[M_REG_S] & R_V7M_FPCCR_S_MASK; - bool lspact =3D env->v7m.fpccr[fpccr_s] & R_V7M_FPCCR_LSPACT_MASK; - - if (lspact && arm_feature(env, ARM_FEATURE_M_SECURITY)) { - qemu_log_mask(CPU_LOG_INT, - "...SecureFault because LSPACT and FPCA both set= \n"); - env->v7m.sfsr |=3D R_V7M_SFSR_LSERR_MASK; - armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_SECURE, false); - } else if (!env->v7m.secure && !nsacr_cp10) { - qemu_log_mask(CPU_LOG_INT, - "...Secure UsageFault with CFSR.NOCP because " - "NSACR.CP10 prevents stacking FP regs\n"); - armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_USAGE, M_REG_S); - env->v7m.cfsr[M_REG_S] |=3D R_V7M_CFSR_NOCP_MASK; - } else { - if (!(env->v7m.fpccr[M_REG_S] & R_V7M_FPCCR_LSPEN_MASK)) { - /* Lazy stacking disabled, save registers now */ - int i; - bool cpacr_pass =3D v7m_cpacr_pass(env, env->v7m.secure, - arm_current_el(env) !=3D = 0); - - if (stacked_ok && !cpacr_pass) { - /* - * Take UsageFault if CPACR forbids access. The pseudo= code - * here does a full CheckCPEnabled() but we know the N= SACR - * check can never fail as we have already handled tha= t. - */ - qemu_log_mask(CPU_LOG_INT, - "...UsageFault with CFSR.NOCP because " - "CPACR.CP10 prevents stacking FP regs\n"= ); - armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_USAGE, - env->v7m.secure); - env->v7m.cfsr[env->v7m.secure] |=3D R_V7M_CFSR_NOCP_MA= SK; - stacked_ok =3D false; - } - - for (i =3D 0; i < ((framesize =3D=3D 0xa8) ? 32 : 16); i += =3D 2) { - uint64_t dn =3D *aa32_vfp_dreg(env, i / 2); - uint32_t faddr =3D frameptr + 0x20 + 4 * i; - uint32_t slo =3D extract64(dn, 0, 32); - uint32_t shi =3D extract64(dn, 32, 32); - - if (i >=3D 16) { - faddr +=3D 8; /* skip the slot for the FPSCR */ - } - stacked_ok =3D stacked_ok && - v7m_stack_write(cpu, faddr, slo, - mmu_idx, STACK_NORMAL) && - v7m_stack_write(cpu, faddr + 4, shi, - mmu_idx, STACK_NORMAL); - } - stacked_ok =3D stacked_ok && - v7m_stack_write(cpu, frameptr + 0x60, - vfp_get_fpscr(env), mmu_idx, STACK_NOR= MAL); - if (cpacr_pass) { - for (i =3D 0; i < ((framesize =3D=3D 0xa8) ? 32 : 16);= i +=3D 2) { - *aa32_vfp_dreg(env, i / 2) =3D 0; - } - vfp_set_fpscr(env, 0); - } - } else { - /* Lazy stacking enabled, save necessary info to stack lat= er */ - v7m_update_fpccr(env, frameptr + 0x20, true); - } - } - } - - /* - * If we broke a stack limit then SP was already updated earlier; - * otherwise we update SP regardless of whether any of the stack - * accesses failed or we took some other kind of fault. - */ - if (!limitviol) { - env->regs[13] =3D frameptr; - } - - return !stacked_ok; -} - -static void do_v7m_exception_exit(ARMCPU *cpu) -{ - CPUARMState *env =3D &cpu->env; - uint32_t excret; - uint32_t xpsr, xpsr_mask; - bool ufault =3D false; - bool sfault =3D false; - bool return_to_sp_process; - bool return_to_handler; - bool rettobase =3D false; - bool exc_secure =3D false; - bool return_to_secure; - bool ftype; - bool restore_s16_s31; - - /* - * If we're not in Handler mode then jumps to magic exception-exit - * addresses don't have magic behaviour. However for the v8M - * security extensions the magic secure-function-return has to - * work in thread mode too, so to avoid doing an extra check in - * the generated code we allow exception-exit magic to also cause the - * internal exception and bring us here in thread mode. Correct code - * will never try to do this (the following insn fetch will always - * fault) so we the overhead of having taken an unnecessary exception - * doesn't matter. - */ - if (!arm_v7m_is_handler_mode(env)) { - return; - } - - /* - * In the spec pseudocode ExceptionReturn() is called directly - * from BXWritePC() and gets the full target PC value including - * bit zero. In QEMU's implementation we treat it as a normal - * jump-to-register (which is then caught later on), and so split - * the target value up between env->regs[15] and env->thumb in - * gen_bx(). Reconstitute it. - */ - excret =3D env->regs[15]; - if (env->thumb) { - excret |=3D 1; - } - - qemu_log_mask(CPU_LOG_INT, "Exception return: magic PC %" PRIx32 - " previous exception %d\n", - excret, env->v7m.exception); - - if ((excret & R_V7M_EXCRET_RES1_MASK) !=3D R_V7M_EXCRET_RES1_MASK) { - qemu_log_mask(LOG_GUEST_ERROR, "M profile: zero high bits in excep= tion " - "exit PC value 0x%" PRIx32 " are UNPREDICTABLE\n", - excret); - } - - ftype =3D excret & R_V7M_EXCRET_FTYPE_MASK; - - if (!arm_feature(env, ARM_FEATURE_VFP) && !ftype) { - qemu_log_mask(LOG_GUEST_ERROR, "M profile: zero FTYPE in exception= " - "exit PC value 0x%" PRIx32 " is UNPREDICTABLE " - "if FPU not present\n", - excret); - ftype =3D true; - } - - if (arm_feature(env, ARM_FEATURE_M_SECURITY)) { - /* - * EXC_RETURN.ES validation check (R_SMFL). We must do this before - * we pick which FAULTMASK to clear. - */ - if (!env->v7m.secure && - ((excret & R_V7M_EXCRET_ES_MASK) || - !(excret & R_V7M_EXCRET_DCRS_MASK))) { - sfault =3D 1; - /* For all other purposes, treat ES as 0 (R_HXSR) */ - excret &=3D ~R_V7M_EXCRET_ES_MASK; - } - exc_secure =3D excret & R_V7M_EXCRET_ES_MASK; - } - - if (env->v7m.exception !=3D ARMV7M_EXCP_NMI) { - /* - * Auto-clear FAULTMASK on return from other than NMI. - * If the security extension is implemented then this only - * happens if the raw execution priority is >=3D 0; the - * value of the ES bit in the exception return value indicates - * which security state's faultmask to clear. (v8M ARM ARM R_KBNF.) - */ - if (arm_feature(env, ARM_FEATURE_M_SECURITY)) { - if (armv7m_nvic_raw_execution_priority(env->nvic) >=3D 0) { - env->v7m.faultmask[exc_secure] =3D 0; - } - } else { - env->v7m.faultmask[M_REG_NS] =3D 0; - } - } - - switch (armv7m_nvic_complete_irq(env->nvic, env->v7m.exception, - exc_secure)) { - case -1: - /* attempt to exit an exception that isn't active */ - ufault =3D true; - break; - case 0: - /* still an irq active now */ - break; - case 1: - /* - * We returned to base exception level, no nesting. - * (In the pseudocode this is written using "NestedActivation !=3D= 1" - * where we have 'rettobase =3D=3D false'.) - */ - rettobase =3D true; - break; - default: - g_assert_not_reached(); - } - - return_to_handler =3D !(excret & R_V7M_EXCRET_MODE_MASK); - return_to_sp_process =3D excret & R_V7M_EXCRET_SPSEL_MASK; - return_to_secure =3D arm_feature(env, ARM_FEATURE_M_SECURITY) && - (excret & R_V7M_EXCRET_S_MASK); - - if (arm_feature(env, ARM_FEATURE_V8)) { - if (!arm_feature(env, ARM_FEATURE_M_SECURITY)) { - /* - * UNPREDICTABLE if S =3D=3D 1 or DCRS =3D=3D 0 or ES =3D=3D 1= (R_XLCP); - * we choose to take the UsageFault. - */ - if ((excret & R_V7M_EXCRET_S_MASK) || - (excret & R_V7M_EXCRET_ES_MASK) || - !(excret & R_V7M_EXCRET_DCRS_MASK)) { - ufault =3D true; - } - } - if (excret & R_V7M_EXCRET_RES0_MASK) { - ufault =3D true; - } - } else { - /* For v7M we only recognize certain combinations of the low bits = */ - switch (excret & 0xf) { - case 1: /* Return to Handler */ - break; - case 13: /* Return to Thread using Process stack */ - case 9: /* Return to Thread using Main stack */ - /* - * We only need to check NONBASETHRDENA for v7M, because in - * v8M this bit does not exist (it is RES1). - */ - if (!rettobase && - !(env->v7m.ccr[env->v7m.secure] & - R_V7M_CCR_NONBASETHRDENA_MASK)) { - ufault =3D true; - } - break; - default: - ufault =3D true; - } - } - - /* - * Set CONTROL.SPSEL from excret.SPSEL. Since we're still in - * Handler mode (and will be until we write the new XPSR.Interrupt - * field) this does not switch around the current stack pointer. - * We must do this before we do any kind of tailchaining, including - * for the derived exceptions on integrity check failures, or we will - * give the guest an incorrect EXCRET.SPSEL value on exception entry. - */ - write_v7m_control_spsel_for_secstate(env, return_to_sp_process, exc_se= cure); - - /* - * Clear scratch FP values left in caller saved registers; this - * must happen before any kind of tail chaining. - */ - if ((env->v7m.fpccr[M_REG_S] & R_V7M_FPCCR_CLRONRET_MASK) && - (env->v7m.control[M_REG_S] & R_V7M_CONTROL_FPCA_MASK)) { - if (env->v7m.fpccr[M_REG_S] & R_V7M_FPCCR_LSPACT_MASK) { - env->v7m.sfsr |=3D R_V7M_SFSR_LSERR_MASK; - armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_SECURE, false); - qemu_log_mask(CPU_LOG_INT, "...taking SecureFault on existing " - "stackframe: error during lazy state deactivatio= n\n"); - v7m_exception_taken(cpu, excret, true, false); - return; - } else { - /* Clear s0..s15 and FPSCR */ - int i; - - for (i =3D 0; i < 16; i +=3D 2) { - *aa32_vfp_dreg(env, i / 2) =3D 0; - } - vfp_set_fpscr(env, 0); - } - } - - if (sfault) { - env->v7m.sfsr |=3D R_V7M_SFSR_INVER_MASK; - armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_SECURE, false); - qemu_log_mask(CPU_LOG_INT, "...taking SecureFault on existing " - "stackframe: failed EXC_RETURN.ES validity check\n"); - v7m_exception_taken(cpu, excret, true, false); - return; - } - - if (ufault) { - /* - * Bad exception return: instead of popping the exception - * stack, directly take a usage fault on the current stack. - */ - env->v7m.cfsr[env->v7m.secure] |=3D R_V7M_CFSR_INVPC_MASK; - armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_USAGE, env->v7m.sec= ure); - qemu_log_mask(CPU_LOG_INT, "...taking UsageFault on existing " - "stackframe: failed exception return integrity check= \n"); - v7m_exception_taken(cpu, excret, true, false); - return; - } - - /* - * Tailchaining: if there is currently a pending exception that - * is high enough priority to preempt execution at the level we're - * about to return to, then just directly take that exception now, - * avoiding an unstack-and-then-stack. Note that now we have - * deactivated the previous exception by calling armv7m_nvic_complete_= irq() - * our current execution priority is already the execution priority we= are - * returning to -- none of the state we would unstack or set based on - * the EXCRET value affects it. - */ - if (armv7m_nvic_can_take_pending_exception(env->nvic)) { - qemu_log_mask(CPU_LOG_INT, "...tailchaining to pending exception\n= "); - v7m_exception_taken(cpu, excret, true, false); - return; - } - - switch_v7m_security_state(env, return_to_secure); - - { - /* - * The stack pointer we should be reading the exception frame from - * depends on bits in the magic exception return type value (and - * for v8M isn't necessarily the stack pointer we will eventually - * end up resuming execution with). Get a pointer to the location - * in the CPU state struct where the SP we need is currently being - * stored; we will use and modify it in place. - * We use this limited C variable scope so we don't accidentally - * use 'frame_sp_p' after we do something that makes it invalid. - */ - uint32_t *frame_sp_p =3D get_v7m_sp_ptr(env, - return_to_secure, - !return_to_handler, - return_to_sp_process); - uint32_t frameptr =3D *frame_sp_p; - bool pop_ok =3D true; - ARMMMUIdx mmu_idx; - bool return_to_priv =3D return_to_handler || - !(env->v7m.control[return_to_secure] & R_V7M_CONTROL_NPRIV_MAS= K); - - mmu_idx =3D arm_v7m_mmu_idx_for_secstate_and_priv(env, return_to_s= ecure, - return_to_priv); - - if (!QEMU_IS_ALIGNED(frameptr, 8) && - arm_feature(env, ARM_FEATURE_V8)) { - qemu_log_mask(LOG_GUEST_ERROR, - "M profile exception return with non-8-aligned S= P " - "for destination state is UNPREDICTABLE\n"); - } - - /* Do we need to pop callee-saved registers? */ - if (return_to_secure && - ((excret & R_V7M_EXCRET_ES_MASK) =3D=3D 0 || - (excret & R_V7M_EXCRET_DCRS_MASK) =3D=3D 0)) { - uint32_t actual_sig; - - pop_ok =3D v7m_stack_read(cpu, &actual_sig, frameptr, mmu_idx); - - if (pop_ok && v7m_integrity_sig(env, excret) !=3D actual_sig) { - /* Take a SecureFault on the current stack */ - env->v7m.sfsr |=3D R_V7M_SFSR_INVIS_MASK; - armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_SECURE, fal= se); - qemu_log_mask(CPU_LOG_INT, "...taking SecureFault on exist= ing " - "stackframe: failed exception return integri= ty " - "signature check\n"); - v7m_exception_taken(cpu, excret, true, false); - return; - } - - pop_ok =3D pop_ok && - v7m_stack_read(cpu, &env->regs[4], frameptr + 0x8, mmu_idx= ) && - v7m_stack_read(cpu, &env->regs[5], frameptr + 0xc, mmu_idx= ) && - v7m_stack_read(cpu, &env->regs[6], frameptr + 0x10, mmu_id= x) && - v7m_stack_read(cpu, &env->regs[7], frameptr + 0x14, mmu_id= x) && - v7m_stack_read(cpu, &env->regs[8], frameptr + 0x18, mmu_id= x) && - v7m_stack_read(cpu, &env->regs[9], frameptr + 0x1c, mmu_id= x) && - v7m_stack_read(cpu, &env->regs[10], frameptr + 0x20, mmu_i= dx) && - v7m_stack_read(cpu, &env->regs[11], frameptr + 0x24, mmu_i= dx); - - frameptr +=3D 0x28; - } - - /* Pop registers */ - pop_ok =3D pop_ok && - v7m_stack_read(cpu, &env->regs[0], frameptr, mmu_idx) && - v7m_stack_read(cpu, &env->regs[1], frameptr + 0x4, mmu_idx) && - v7m_stack_read(cpu, &env->regs[2], frameptr + 0x8, mmu_idx) && - v7m_stack_read(cpu, &env->regs[3], frameptr + 0xc, mmu_idx) && - v7m_stack_read(cpu, &env->regs[12], frameptr + 0x10, mmu_idx) = && - v7m_stack_read(cpu, &env->regs[14], frameptr + 0x14, mmu_idx) = && - v7m_stack_read(cpu, &env->regs[15], frameptr + 0x18, mmu_idx) = && - v7m_stack_read(cpu, &xpsr, frameptr + 0x1c, mmu_idx); - - if (!pop_ok) { - /* - * v7m_stack_read() pended a fault, so take it (as a tail - * chained exception on the same stack frame) - */ - qemu_log_mask(CPU_LOG_INT, "...derived exception on unstacking= \n"); - v7m_exception_taken(cpu, excret, true, false); - return; - } - - /* - * Returning from an exception with a PC with bit 0 set is defined - * behaviour on v8M (bit 0 is ignored), but for v7M it was specifi= ed - * to be UNPREDICTABLE. In practice actual v7M hardware seems to i= gnore - * the lsbit, and there are several RTOSes out there which incorre= ctly - * assume the r15 in the stack frame should be a Thumb-style "lsbit - * indicates ARM/Thumb" value, so ignore the bit on v7M as well, b= ut - * complain about the badly behaved guest. - */ - if (env->regs[15] & 1) { - env->regs[15] &=3D ~1U; - if (!arm_feature(env, ARM_FEATURE_V8)) { - qemu_log_mask(LOG_GUEST_ERROR, - "M profile return from interrupt with misali= gned " - "PC is UNPREDICTABLE on v7M\n"); - } - } - - if (arm_feature(env, ARM_FEATURE_V8)) { - /* - * For v8M we have to check whether the xPSR exception field - * matches the EXCRET value for return to handler/thread - * before we commit to changing the SP and xPSR. - */ - bool will_be_handler =3D (xpsr & XPSR_EXCP) !=3D 0; - if (return_to_handler !=3D will_be_handler) { - /* - * Take an INVPC UsageFault on the current stack. - * By this point we will have switched to the security sta= te - * for the background state, so this UsageFault will target - * that state. - */ - armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_USAGE, - env->v7m.secure); - env->v7m.cfsr[env->v7m.secure] |=3D R_V7M_CFSR_INVPC_MASK; - qemu_log_mask(CPU_LOG_INT, "...taking UsageFault on existi= ng " - "stackframe: failed exception return integri= ty " - "check\n"); - v7m_exception_taken(cpu, excret, true, false); - return; - } - } - - if (!ftype) { - /* FP present and we need to handle it */ - if (!return_to_secure && - (env->v7m.fpccr[M_REG_S] & R_V7M_FPCCR_LSPACT_MASK)) { - armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_SECURE, fal= se); - env->v7m.sfsr |=3D R_V7M_SFSR_LSERR_MASK; - qemu_log_mask(CPU_LOG_INT, - "...taking SecureFault on existing stackfram= e: " - "Secure LSPACT set but exception return is " - "not to secure state\n"); - v7m_exception_taken(cpu, excret, true, false); - return; - } - - restore_s16_s31 =3D return_to_secure && - (env->v7m.fpccr[M_REG_S] & R_V7M_FPCCR_TS_MASK); - - if (env->v7m.fpccr[return_to_secure] & R_V7M_FPCCR_LSPACT_MASK= ) { - /* State in FPU is still valid, just clear LSPACT */ - env->v7m.fpccr[return_to_secure] &=3D ~R_V7M_FPCCR_LSPACT_= MASK; - } else { - int i; - uint32_t fpscr; - bool cpacr_pass, nsacr_pass; - - cpacr_pass =3D v7m_cpacr_pass(env, return_to_secure, - return_to_priv); - nsacr_pass =3D return_to_secure || - extract32(env->v7m.nsacr, 10, 1); - - if (!cpacr_pass) { - armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_USAGE, - return_to_secure); - env->v7m.cfsr[return_to_secure] |=3D R_V7M_CFSR_NOCP_M= ASK; - qemu_log_mask(CPU_LOG_INT, - "...taking UsageFault on existing " - "stackframe: CPACR.CP10 prevents unstack= ing " - "FP regs\n"); - v7m_exception_taken(cpu, excret, true, false); - return; - } else if (!nsacr_pass) { - armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_USAGE, = true); - env->v7m.cfsr[M_REG_S] |=3D R_V7M_CFSR_INVPC_MASK; - qemu_log_mask(CPU_LOG_INT, - "...taking Secure UsageFault on existing= " - "stackframe: NSACR.CP10 prevents unstack= ing " - "FP regs\n"); - v7m_exception_taken(cpu, excret, true, false); - return; - } - - for (i =3D 0; i < (restore_s16_s31 ? 32 : 16); i +=3D 2) { - uint32_t slo, shi; - uint64_t dn; - uint32_t faddr =3D frameptr + 0x20 + 4 * i; - - if (i >=3D 16) { - faddr +=3D 8; /* Skip the slot for the FPSCR */ - } - - pop_ok =3D pop_ok && - v7m_stack_read(cpu, &slo, faddr, mmu_idx) && - v7m_stack_read(cpu, &shi, faddr + 4, mmu_idx); - - if (!pop_ok) { - break; - } - - dn =3D (uint64_t)shi << 32 | slo; - *aa32_vfp_dreg(env, i / 2) =3D dn; - } - pop_ok =3D pop_ok && - v7m_stack_read(cpu, &fpscr, frameptr + 0x60, mmu_idx); - if (pop_ok) { - vfp_set_fpscr(env, fpscr); - } - if (!pop_ok) { - /* - * These regs are 0 if security extension present; - * otherwise merely UNKNOWN. We zero always. - */ - for (i =3D 0; i < (restore_s16_s31 ? 32 : 16); i +=3D = 2) { - *aa32_vfp_dreg(env, i / 2) =3D 0; - } - vfp_set_fpscr(env, 0); - } - } - } - env->v7m.control[M_REG_S] =3D FIELD_DP32(env->v7m.control[M_REG_S], - V7M_CONTROL, FPCA, !ftype); - - /* Commit to consuming the stack frame */ - frameptr +=3D 0x20; - if (!ftype) { - frameptr +=3D 0x48; - if (restore_s16_s31) { - frameptr +=3D 0x40; - } - } - /* - * Undo stack alignment (the SPREALIGN bit indicates that the orig= inal - * pre-exception SP was not 8-aligned and we added a padding word = to - * align it, so we undo this by ORing in the bit that increases it - * from the current 8-aligned value to the 8-unaligned value. (Add= ing 4 - * would work too but a logical OR is how the pseudocode specifies= it.) - */ - if (xpsr & XPSR_SPREALIGN) { - frameptr |=3D 4; - } - *frame_sp_p =3D frameptr; - } - - xpsr_mask =3D ~(XPSR_SPREALIGN | XPSR_SFPA); - if (!arm_feature(env, ARM_FEATURE_THUMB_DSP)) { - xpsr_mask &=3D ~XPSR_GE; - } - /* This xpsr_write() will invalidate frame_sp_p as it may switch stack= */ - xpsr_write(env, xpsr, xpsr_mask); - - if (env->v7m.secure) { - bool sfpa =3D xpsr & XPSR_SFPA; - - env->v7m.control[M_REG_S] =3D FIELD_DP32(env->v7m.control[M_REG_S], - V7M_CONTROL, SFPA, sfpa); - } - - /* - * The restored xPSR exception field will be zero if we're - * resuming in Thread mode. If that doesn't match what the - * exception return excret specified then this is a UsageFault. - * v7M requires we make this check here; v8M did it earlier. - */ - if (return_to_handler !=3D arm_v7m_is_handler_mode(env)) { - /* - * Take an INVPC UsageFault by pushing the stack again; - * we know we're v7M so this is never a Secure UsageFault. - */ - bool ignore_stackfaults; - - assert(!arm_feature(env, ARM_FEATURE_V8)); - armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_USAGE, false); - env->v7m.cfsr[env->v7m.secure] |=3D R_V7M_CFSR_INVPC_MASK; - ignore_stackfaults =3D v7m_push_stack(cpu); - qemu_log_mask(CPU_LOG_INT, "...taking UsageFault on new stackframe= : " - "failed exception return integrity check\n"); - v7m_exception_taken(cpu, excret, false, ignore_stackfaults); - return; - } - - /* Otherwise, we have a successful exception exit. */ - arm_clear_exclusive(env); - qemu_log_mask(CPU_LOG_INT, "...successful exception return\n"); -} - -static bool do_v7m_function_return(ARMCPU *cpu) -{ - /* - * v8M security extensions magic function return. - * We may either: - * (1) throw an exception (longjump) - * (2) return true if we successfully handled the function return - * (3) return false if we failed a consistency check and have - * pended a UsageFault that needs to be taken now - * - * At this point the magic return value is split between env->regs[15] - * and env->thumb. We don't bother to reconstitute it because we don't - * need it (all values are handled the same way). - */ - CPUARMState *env =3D &cpu->env; - uint32_t newpc, newpsr, newpsr_exc; - - qemu_log_mask(CPU_LOG_INT, "...really v7M secure function return\n"); - - { - bool threadmode, spsel; - TCGMemOpIdx oi; - ARMMMUIdx mmu_idx; - uint32_t *frame_sp_p; - uint32_t frameptr; - - /* Pull the return address and IPSR from the Secure stack */ - threadmode =3D !arm_v7m_is_handler_mode(env); - spsel =3D env->v7m.control[M_REG_S] & R_V7M_CONTROL_SPSEL_MASK; - - frame_sp_p =3D get_v7m_sp_ptr(env, true, threadmode, spsel); - frameptr =3D *frame_sp_p; - - /* - * These loads may throw an exception (for MPU faults). We want to - * do them as secure, so work out what MMU index that is. - */ - mmu_idx =3D arm_v7m_mmu_idx_for_secstate(env, true); - oi =3D make_memop_idx(MO_LE, arm_to_core_mmu_idx(mmu_idx)); - newpc =3D helper_le_ldul_mmu(env, frameptr, oi, 0); - newpsr =3D helper_le_ldul_mmu(env, frameptr + 4, oi, 0); - - /* Consistency checks on new IPSR */ - newpsr_exc =3D newpsr & XPSR_EXCP; - if (!((env->v7m.exception =3D=3D 0 && newpsr_exc =3D=3D 0) || - (env->v7m.exception =3D=3D 1 && newpsr_exc !=3D 0))) { - /* Pend the fault and tell our caller to take it */ - env->v7m.cfsr[env->v7m.secure] |=3D R_V7M_CFSR_INVPC_MASK; - armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_USAGE, - env->v7m.secure); - qemu_log_mask(CPU_LOG_INT, - "...taking INVPC UsageFault: " - "IPSR consistency check failed\n"); - return false; - } - - *frame_sp_p =3D frameptr + 8; - } - - /* This invalidates frame_sp_p */ - switch_v7m_security_state(env, true); - env->v7m.exception =3D newpsr_exc; - env->v7m.control[M_REG_S] &=3D ~R_V7M_CONTROL_SFPA_MASK; - if (newpsr & XPSR_SFPA) { - env->v7m.control[M_REG_S] |=3D R_V7M_CONTROL_SFPA_MASK; - } - xpsr_write(env, 0, XPSR_IT); - env->thumb =3D newpc & 1; - env->regs[15] =3D newpc & ~1; - - qemu_log_mask(CPU_LOG_INT, "...function return successful\n"); - return true; -} - -static bool v7m_read_half_insn(ARMCPU *cpu, ARMMMUIdx mmu_idx, - uint32_t addr, uint16_t *insn) -{ - /* - * Load a 16-bit portion of a v7M instruction, returning true on succe= ss, - * or false on failure (in which case we will have pended the appropri= ate - * exception). - * We need to do the instruction fetch's MPU and SAU checks - * like this because there is no MMU index that would allow - * doing the load with a single function call. Instead we must - * first check that the security attributes permit the load - * and that they don't mismatch on the two halves of the instruction, - * and then we do the load as a secure load (ie using the security - * attributes of the address, not the CPU, as architecturally required= ). - */ - CPUState *cs =3D CPU(cpu); - CPUARMState *env =3D &cpu->env; - V8M_SAttributes sattrs =3D {}; - MemTxAttrs attrs =3D {}; - ARMMMUFaultInfo fi =3D {}; - MemTxResult txres; - target_ulong page_size; - hwaddr physaddr; - int prot; - - v8m_security_lookup(env, addr, MMU_INST_FETCH, mmu_idx, &sattrs); - if (!sattrs.nsc || sattrs.ns) { - /* - * This must be the second half of the insn, and it straddles a - * region boundary with the second half not being S&NSC. - */ - env->v7m.sfsr |=3D R_V7M_SFSR_INVEP_MASK; - armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_SECURE, false); - qemu_log_mask(CPU_LOG_INT, - "...really SecureFault with SFSR.INVEP\n"); - return false; - } - if (get_phys_addr(env, addr, MMU_INST_FETCH, mmu_idx, - &physaddr, &attrs, &prot, &page_size, &fi, NULL)) { - /* the MPU lookup failed */ - env->v7m.cfsr[env->v7m.secure] |=3D R_V7M_CFSR_IACCVIOL_MASK; - armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_MEM, env->v7m.secur= e); - qemu_log_mask(CPU_LOG_INT, "...really MemManage with CFSR.IACCVIOL= \n"); - return false; - } - *insn =3D address_space_lduw_le(arm_addressspace(cs, attrs), physaddr, - attrs, &txres); - if (txres !=3D MEMTX_OK) { - env->v7m.cfsr[M_REG_NS] |=3D R_V7M_CFSR_IBUSERR_MASK; - armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_BUS, false); - qemu_log_mask(CPU_LOG_INT, "...really BusFault with CFSR.IBUSERR\n= "); - return false; - } - return true; -} - -static bool v7m_handle_execute_nsc(ARMCPU *cpu) -{ - /* - * Check whether this attempt to execute code in a Secure & NS-Callable - * memory region is for an SG instruction; if so, then emulate the - * effect of the SG instruction and return true. Otherwise pend - * the correct kind of exception and return false. - */ - CPUARMState *env =3D &cpu->env; - ARMMMUIdx mmu_idx; - uint16_t insn; - - /* - * We should never get here unless get_phys_addr_pmsav8() caused - * an exception for NS executing in S&NSC memory. - */ - assert(!env->v7m.secure); - assert(arm_feature(env, ARM_FEATURE_M_SECURITY)); - - /* We want to do the MPU lookup as secure; work out what mmu_idx that = is */ - mmu_idx =3D arm_v7m_mmu_idx_for_secstate(env, true); - - if (!v7m_read_half_insn(cpu, mmu_idx, env->regs[15], &insn)) { - return false; - } - - if (!env->thumb) { - goto gen_invep; - } - - if (insn !=3D 0xe97f) { - /* - * Not an SG instruction first half (we choose the IMPDEF - * early-SG-check option). - */ - goto gen_invep; - } - - if (!v7m_read_half_insn(cpu, mmu_idx, env->regs[15] + 2, &insn)) { - return false; - } - - if (insn !=3D 0xe97f) { - /* - * Not an SG instruction second half (yes, both halves of the SG - * insn have the same hex value) - */ - goto gen_invep; - } - - /* - * OK, we have confirmed that we really have an SG instruction. - * We know we're NS in S memory so don't need to repeat those checks. - */ - qemu_log_mask(CPU_LOG_INT, "...really an SG instruction at 0x%08" PRIx= 32 - ", executing it\n", env->regs[15]); - env->regs[14] &=3D ~1; - env->v7m.control[M_REG_S] &=3D ~R_V7M_CONTROL_SFPA_MASK; - switch_v7m_security_state(env, true); - xpsr_write(env, 0, XPSR_IT); - env->regs[15] +=3D 4; - return true; - -gen_invep: - env->v7m.sfsr |=3D R_V7M_SFSR_INVEP_MASK; - armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_SECURE, false); - qemu_log_mask(CPU_LOG_INT, - "...really SecureFault with SFSR.INVEP\n"); - return false; -} - -void arm_v7m_cpu_do_interrupt(CPUState *cs) -{ - ARMCPU *cpu =3D ARM_CPU(cs); - CPUARMState *env =3D &cpu->env; - uint32_t lr; - bool ignore_stackfaults; - - arm_log_exception(cs->exception_index); - - /* - * For exceptions we just mark as pending on the NVIC, and let that - * handle it. - */ - switch (cs->exception_index) { - case EXCP_UDEF: - armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_USAGE, env->v7m.sec= ure); - env->v7m.cfsr[env->v7m.secure] |=3D R_V7M_CFSR_UNDEFINSTR_MASK; - break; - case EXCP_NOCP: - { - /* - * NOCP might be directed to something other than the current - * security state if this fault is because of NSACR; we indicate - * the target security state using exception.target_el. - */ - int target_secstate; - - if (env->exception.target_el =3D=3D 3) { - target_secstate =3D M_REG_S; - } else { - target_secstate =3D env->v7m.secure; - } - armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_USAGE, target_secst= ate); - env->v7m.cfsr[target_secstate] |=3D R_V7M_CFSR_NOCP_MASK; - break; - } - case EXCP_INVSTATE: - armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_USAGE, env->v7m.sec= ure); - env->v7m.cfsr[env->v7m.secure] |=3D R_V7M_CFSR_INVSTATE_MASK; - break; - case EXCP_STKOF: - armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_USAGE, env->v7m.sec= ure); - env->v7m.cfsr[env->v7m.secure] |=3D R_V7M_CFSR_STKOF_MASK; - break; - case EXCP_LSERR: - armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_SECURE, false); - env->v7m.sfsr |=3D R_V7M_SFSR_LSERR_MASK; - break; - case EXCP_UNALIGNED: - armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_USAGE, env->v7m.sec= ure); - env->v7m.cfsr[env->v7m.secure] |=3D R_V7M_CFSR_UNALIGNED_MASK; - break; - case EXCP_SWI: - /* The PC already points to the next instruction. */ - armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_SVC, env->v7m.secur= e); - break; - case EXCP_PREFETCH_ABORT: - case EXCP_DATA_ABORT: - /* - * Note that for M profile we don't have a guest facing FSR, but - * the env->exception.fsr will be populated by the code that - * raises the fault, in the A profile short-descriptor format. - */ - switch (env->exception.fsr & 0xf) { - case M_FAKE_FSR_NSC_EXEC: - /* - * Exception generated when we try to execute code at an addre= ss - * which is marked as Secure & Non-Secure Callable and the CPU - * is in the Non-Secure state. The only instruction which can - * be executed like this is SG (and that only if both halves of - * the SG instruction have the same security attributes.) - * Everything else must generate an INVEP SecureFault, so we - * emulate the SG instruction here. - */ - if (v7m_handle_execute_nsc(cpu)) { - return; - } - break; - case M_FAKE_FSR_SFAULT: - /* - * Various flavours of SecureFault for attempts to execute or - * access data in the wrong security state. - */ - switch (cs->exception_index) { - case EXCP_PREFETCH_ABORT: - if (env->v7m.secure) { - env->v7m.sfsr |=3D R_V7M_SFSR_INVTRAN_MASK; - qemu_log_mask(CPU_LOG_INT, - "...really SecureFault with SFSR.INVTRAN= \n"); - } else { - env->v7m.sfsr |=3D R_V7M_SFSR_INVEP_MASK; - qemu_log_mask(CPU_LOG_INT, - "...really SecureFault with SFSR.INVEP\n= "); - } - break; - case EXCP_DATA_ABORT: - /* This must be an NS access to S memory */ - env->v7m.sfsr |=3D R_V7M_SFSR_AUVIOL_MASK; - qemu_log_mask(CPU_LOG_INT, - "...really SecureFault with SFSR.AUVIOL\n"); - break; - } - armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_SECURE, false); - break; - case 0x8: /* External Abort */ - switch (cs->exception_index) { - case EXCP_PREFETCH_ABORT: - env->v7m.cfsr[M_REG_NS] |=3D R_V7M_CFSR_IBUSERR_MASK; - qemu_log_mask(CPU_LOG_INT, "...with CFSR.IBUSERR\n"); - break; - case EXCP_DATA_ABORT: - env->v7m.cfsr[M_REG_NS] |=3D - (R_V7M_CFSR_PRECISERR_MASK | R_V7M_CFSR_BFARVALID_MASK= ); - env->v7m.bfar =3D env->exception.vaddress; - qemu_log_mask(CPU_LOG_INT, - "...with CFSR.PRECISERR and BFAR 0x%x\n", - env->v7m.bfar); - break; - } - armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_BUS, false); - break; - default: - /* - * All other FSR values are either MPU faults or "can't happen - * for M profile" cases. - */ - switch (cs->exception_index) { - case EXCP_PREFETCH_ABORT: - env->v7m.cfsr[env->v7m.secure] |=3D R_V7M_CFSR_IACCVIOL_MA= SK; - qemu_log_mask(CPU_LOG_INT, "...with CFSR.IACCVIOL\n"); - break; - case EXCP_DATA_ABORT: - env->v7m.cfsr[env->v7m.secure] |=3D - (R_V7M_CFSR_DACCVIOL_MASK | R_V7M_CFSR_MMARVALID_MASK); - env->v7m.mmfar[env->v7m.secure] =3D env->exception.vaddres= s; - qemu_log_mask(CPU_LOG_INT, - "...with CFSR.DACCVIOL and MMFAR 0x%x\n", - env->v7m.mmfar[env->v7m.secure]); - break; - } - armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_MEM, - env->v7m.secure); - break; - } - break; - case EXCP_BKPT: - if (semihosting_enabled()) { - int nr; - nr =3D arm_lduw_code(env, env->regs[15], arm_sctlr_b(env)) & 0= xff; - if (nr =3D=3D 0xab) { - env->regs[15] +=3D 2; - qemu_log_mask(CPU_LOG_INT, - "...handling as semihosting call 0x%x\n", - env->regs[0]); - env->regs[0] =3D do_arm_semihosting(env); - return; - } - } - armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_DEBUG, false); - break; - case EXCP_IRQ: - break; - case EXCP_EXCEPTION_EXIT: - if (env->regs[15] < EXC_RETURN_MIN_MAGIC) { - /* Must be v8M security extension function return */ - assert(env->regs[15] >=3D FNC_RETURN_MIN_MAGIC); - assert(arm_feature(env, ARM_FEATURE_M_SECURITY)); - if (do_v7m_function_return(cpu)) { - return; - } - } else { - do_v7m_exception_exit(cpu); - return; - } - break; - case EXCP_LAZYFP: - /* - * We already pended the specific exception in the NVIC in the - * v7m_preserve_fp_state() helper function. - */ - break; - default: - cpu_abort(cs, "Unhandled exception 0x%x\n", cs->exception_index); - return; /* Never happens. Keep compiler happy. */ - } - - if (arm_feature(env, ARM_FEATURE_V8)) { - lr =3D R_V7M_EXCRET_RES1_MASK | - R_V7M_EXCRET_DCRS_MASK; - /* - * The S bit indicates whether we should return to Secure - * or NonSecure (ie our current state). - * The ES bit indicates whether we're taking this exception - * to Secure or NonSecure (ie our target state). We set it - * later, in v7m_exception_taken(). - * The SPSEL bit is also set in v7m_exception_taken() for v8M. - * This corresponds to the ARM ARM pseudocode for v8M setting - * some LR bits in PushStack() and some in ExceptionTaken(); - * the distinction matters for the tailchain cases where we - * can take an exception without pushing the stack. - */ - if (env->v7m.secure) { - lr |=3D R_V7M_EXCRET_S_MASK; - } - if (!(env->v7m.control[M_REG_S] & R_V7M_CONTROL_FPCA_MASK)) { - lr |=3D R_V7M_EXCRET_FTYPE_MASK; - } - } else { - lr =3D R_V7M_EXCRET_RES1_MASK | - R_V7M_EXCRET_S_MASK | - R_V7M_EXCRET_DCRS_MASK | - R_V7M_EXCRET_FTYPE_MASK | - R_V7M_EXCRET_ES_MASK; - if (env->v7m.control[M_REG_NS] & R_V7M_CONTROL_SPSEL_MASK) { - lr |=3D R_V7M_EXCRET_SPSEL_MASK; - } - } - if (!arm_v7m_is_handler_mode(env)) { - lr |=3D R_V7M_EXCRET_MODE_MASK; - } - - ignore_stackfaults =3D v7m_push_stack(cpu); - v7m_exception_taken(cpu, lr, false, ignore_stackfaults); -} - /* * Function used to synchronize QEMU's AArch64 register set with AArch32 * register set. This is necessary when switching between AArch32 and AAr= ch64 @@ -12731,489 +10590,6 @@ bool get_phys_addr(CPUARMState *env, target_ulong= address, } } =20 -hwaddr arm_cpu_get_phys_page_attrs_debug(CPUState *cs, vaddr addr, - MemTxAttrs *attrs) -{ - ARMCPU *cpu =3D ARM_CPU(cs); - CPUARMState *env =3D &cpu->env; - hwaddr phys_addr; - target_ulong page_size; - int prot; - bool ret; - ARMMMUFaultInfo fi =3D {}; - ARMMMUIdx mmu_idx =3D arm_mmu_idx(env); - - *attrs =3D (MemTxAttrs) {}; - - ret =3D get_phys_addr(env, addr, 0, mmu_idx, &phys_addr, - attrs, &prot, &page_size, &fi, NULL); - - if (ret) { - return -1; - } - return phys_addr; -} - -uint32_t HELPER(v7m_mrs)(CPUARMState *env, uint32_t reg) -{ - uint32_t mask; - unsigned el =3D arm_current_el(env); - - /* First handle registers which unprivileged can read */ - - switch (reg) { - case 0 ... 7: /* xPSR sub-fields */ - mask =3D 0; - if ((reg & 1) && el) { - mask |=3D XPSR_EXCP; /* IPSR (unpriv. reads as zero) */ - } - if (!(reg & 4)) { - mask |=3D XPSR_NZCV | XPSR_Q; /* APSR */ - if (arm_feature(env, ARM_FEATURE_THUMB_DSP)) { - mask |=3D XPSR_GE; - } - } - /* EPSR reads as zero */ - return xpsr_read(env) & mask; - break; - case 20: /* CONTROL */ - { - uint32_t value =3D env->v7m.control[env->v7m.secure]; - if (!env->v7m.secure) { - /* SFPA is RAZ/WI from NS; FPCA is stored in the M_REG_S bank = */ - value |=3D env->v7m.control[M_REG_S] & R_V7M_CONTROL_FPCA_MASK; - } - return value; - } - case 0x94: /* CONTROL_NS */ - /* - * We have to handle this here because unprivileged Secure code - * can read the NS CONTROL register. - */ - if (!env->v7m.secure) { - return 0; - } - return env->v7m.control[M_REG_NS] | - (env->v7m.control[M_REG_S] & R_V7M_CONTROL_FPCA_MASK); - } - - if (el =3D=3D 0) { - return 0; /* unprivileged reads others as zero */ - } - - if (arm_feature(env, ARM_FEATURE_M_SECURITY)) { - switch (reg) { - case 0x88: /* MSP_NS */ - if (!env->v7m.secure) { - return 0; - } - return env->v7m.other_ss_msp; - case 0x89: /* PSP_NS */ - if (!env->v7m.secure) { - return 0; - } - return env->v7m.other_ss_psp; - case 0x8a: /* MSPLIM_NS */ - if (!env->v7m.secure) { - return 0; - } - return env->v7m.msplim[M_REG_NS]; - case 0x8b: /* PSPLIM_NS */ - if (!env->v7m.secure) { - return 0; - } - return env->v7m.psplim[M_REG_NS]; - case 0x90: /* PRIMASK_NS */ - if (!env->v7m.secure) { - return 0; - } - return env->v7m.primask[M_REG_NS]; - case 0x91: /* BASEPRI_NS */ - if (!env->v7m.secure) { - return 0; - } - return env->v7m.basepri[M_REG_NS]; - case 0x93: /* FAULTMASK_NS */ - if (!env->v7m.secure) { - return 0; - } - return env->v7m.faultmask[M_REG_NS]; - case 0x98: /* SP_NS */ - { - /* - * This gives the non-secure SP selected based on whether we're - * currently in handler mode or not, using the NS CONTROL.SPSE= L. - */ - bool spsel =3D env->v7m.control[M_REG_NS] & R_V7M_CONTROL_SPSE= L_MASK; - - if (!env->v7m.secure) { - return 0; - } - if (!arm_v7m_is_handler_mode(env) && spsel) { - return env->v7m.other_ss_psp; - } else { - return env->v7m.other_ss_msp; - } - } - default: - break; - } - } - - switch (reg) { - case 8: /* MSP */ - return v7m_using_psp(env) ? env->v7m.other_sp : env->regs[13]; - case 9: /* PSP */ - return v7m_using_psp(env) ? env->regs[13] : env->v7m.other_sp; - case 10: /* MSPLIM */ - if (!arm_feature(env, ARM_FEATURE_V8)) { - goto bad_reg; - } - return env->v7m.msplim[env->v7m.secure]; - case 11: /* PSPLIM */ - if (!arm_feature(env, ARM_FEATURE_V8)) { - goto bad_reg; - } - return env->v7m.psplim[env->v7m.secure]; - case 16: /* PRIMASK */ - return env->v7m.primask[env->v7m.secure]; - case 17: /* BASEPRI */ - case 18: /* BASEPRI_MAX */ - return env->v7m.basepri[env->v7m.secure]; - case 19: /* FAULTMASK */ - return env->v7m.faultmask[env->v7m.secure]; - default: - bad_reg: - qemu_log_mask(LOG_GUEST_ERROR, "Attempt to read unknown special" - " register %d\n", reg); - return 0; - } -} - -void HELPER(v7m_msr)(CPUARMState *env, uint32_t maskreg, uint32_t val) -{ - /* - * We're passed bits [11..0] of the instruction; extract - * SYSm and the mask bits. - * Invalid combinations of SYSm and mask are UNPREDICTABLE; - * we choose to treat them as if the mask bits were valid. - * NB that the pseudocode 'mask' variable is bits [11..10], - * whereas ours is [11..8]. - */ - uint32_t mask =3D extract32(maskreg, 8, 4); - uint32_t reg =3D extract32(maskreg, 0, 8); - int cur_el =3D arm_current_el(env); - - if (cur_el =3D=3D 0 && reg > 7 && reg !=3D 20) { - /* - * only xPSR sub-fields and CONTROL.SFPA may be written by - * unprivileged code - */ - return; - } - - if (arm_feature(env, ARM_FEATURE_M_SECURITY)) { - switch (reg) { - case 0x88: /* MSP_NS */ - if (!env->v7m.secure) { - return; - } - env->v7m.other_ss_msp =3D val; - return; - case 0x89: /* PSP_NS */ - if (!env->v7m.secure) { - return; - } - env->v7m.other_ss_psp =3D val; - return; - case 0x8a: /* MSPLIM_NS */ - if (!env->v7m.secure) { - return; - } - env->v7m.msplim[M_REG_NS] =3D val & ~7; - return; - case 0x8b: /* PSPLIM_NS */ - if (!env->v7m.secure) { - return; - } - env->v7m.psplim[M_REG_NS] =3D val & ~7; - return; - case 0x90: /* PRIMASK_NS */ - if (!env->v7m.secure) { - return; - } - env->v7m.primask[M_REG_NS] =3D val & 1; - return; - case 0x91: /* BASEPRI_NS */ - if (!env->v7m.secure || !arm_feature(env, ARM_FEATURE_M_MAIN))= { - return; - } - env->v7m.basepri[M_REG_NS] =3D val & 0xff; - return; - case 0x93: /* FAULTMASK_NS */ - if (!env->v7m.secure || !arm_feature(env, ARM_FEATURE_M_MAIN))= { - return; - } - env->v7m.faultmask[M_REG_NS] =3D val & 1; - return; - case 0x94: /* CONTROL_NS */ - if (!env->v7m.secure) { - return; - } - write_v7m_control_spsel_for_secstate(env, - val & R_V7M_CONTROL_SPSEL= _MASK, - M_REG_NS); - if (arm_feature(env, ARM_FEATURE_M_MAIN)) { - env->v7m.control[M_REG_NS] &=3D ~R_V7M_CONTROL_NPRIV_MASK; - env->v7m.control[M_REG_NS] |=3D val & R_V7M_CONTROL_NPRIV_= MASK; - } - /* - * SFPA is RAZ/WI from NS. FPCA is RO if NSACR.CP10 =3D=3D 0, - * RES0 if the FPU is not present, and is stored in the S bank - */ - if (arm_feature(env, ARM_FEATURE_VFP) && - extract32(env->v7m.nsacr, 10, 1)) { - env->v7m.control[M_REG_S] &=3D ~R_V7M_CONTROL_FPCA_MASK; - env->v7m.control[M_REG_S] |=3D val & R_V7M_CONTROL_FPCA_MA= SK; - } - return; - case 0x98: /* SP_NS */ - { - /* - * This gives the non-secure SP selected based on whether we're - * currently in handler mode or not, using the NS CONTROL.SPSE= L. - */ - bool spsel =3D env->v7m.control[M_REG_NS] & R_V7M_CONTROL_SPSE= L_MASK; - bool is_psp =3D !arm_v7m_is_handler_mode(env) && spsel; - uint32_t limit; - - if (!env->v7m.secure) { - return; - } - - limit =3D is_psp ? env->v7m.psplim[false] : env->v7m.msplim[fa= lse]; - - if (val < limit) { - CPUState *cs =3D env_cpu(env); - - cpu_restore_state(cs, GETPC(), true); - raise_exception(env, EXCP_STKOF, 0, 1); - } - - if (is_psp) { - env->v7m.other_ss_psp =3D val; - } else { - env->v7m.other_ss_msp =3D val; - } - return; - } - default: - break; - } - } - - switch (reg) { - case 0 ... 7: /* xPSR sub-fields */ - /* only APSR is actually writable */ - if (!(reg & 4)) { - uint32_t apsrmask =3D 0; - - if (mask & 8) { - apsrmask |=3D XPSR_NZCV | XPSR_Q; - } - if ((mask & 4) && arm_feature(env, ARM_FEATURE_THUMB_DSP)) { - apsrmask |=3D XPSR_GE; - } - xpsr_write(env, val, apsrmask); - } - break; - case 8: /* MSP */ - if (v7m_using_psp(env)) { - env->v7m.other_sp =3D val; - } else { - env->regs[13] =3D val; - } - break; - case 9: /* PSP */ - if (v7m_using_psp(env)) { - env->regs[13] =3D val; - } else { - env->v7m.other_sp =3D val; - } - break; - case 10: /* MSPLIM */ - if (!arm_feature(env, ARM_FEATURE_V8)) { - goto bad_reg; - } - env->v7m.msplim[env->v7m.secure] =3D val & ~7; - break; - case 11: /* PSPLIM */ - if (!arm_feature(env, ARM_FEATURE_V8)) { - goto bad_reg; - } - env->v7m.psplim[env->v7m.secure] =3D val & ~7; - break; - case 16: /* PRIMASK */ - env->v7m.primask[env->v7m.secure] =3D val & 1; - break; - case 17: /* BASEPRI */ - if (!arm_feature(env, ARM_FEATURE_M_MAIN)) { - goto bad_reg; - } - env->v7m.basepri[env->v7m.secure] =3D val & 0xff; - break; - case 18: /* BASEPRI_MAX */ - if (!arm_feature(env, ARM_FEATURE_M_MAIN)) { - goto bad_reg; - } - val &=3D 0xff; - if (val !=3D 0 && (val < env->v7m.basepri[env->v7m.secure] - || env->v7m.basepri[env->v7m.secure] =3D=3D 0)) { - env->v7m.basepri[env->v7m.secure] =3D val; - } - break; - case 19: /* FAULTMASK */ - if (!arm_feature(env, ARM_FEATURE_M_MAIN)) { - goto bad_reg; - } - env->v7m.faultmask[env->v7m.secure] =3D val & 1; - break; - case 20: /* CONTROL */ - /* - * Writing to the SPSEL bit only has an effect if we are in - * thread mode; other bits can be updated by any privileged code. - * write_v7m_control_spsel() deals with updating the SPSEL bit in - * env->v7m.control, so we only need update the others. - * For v7M, we must just ignore explicit writes to SPSEL in handler - * mode; for v8M the write is permitted but will have no effect. - * All these bits are writes-ignored from non-privileged code, - * except for SFPA. - */ - if (cur_el > 0 && (arm_feature(env, ARM_FEATURE_V8) || - !arm_v7m_is_handler_mode(env))) { - write_v7m_control_spsel(env, (val & R_V7M_CONTROL_SPSEL_MASK) = !=3D 0); - } - if (cur_el > 0 && arm_feature(env, ARM_FEATURE_M_MAIN)) { - env->v7m.control[env->v7m.secure] &=3D ~R_V7M_CONTROL_NPRIV_MA= SK; - env->v7m.control[env->v7m.secure] |=3D val & R_V7M_CONTROL_NPR= IV_MASK; - } - if (arm_feature(env, ARM_FEATURE_VFP)) { - /* - * SFPA is RAZ/WI from NS or if no FPU. - * FPCA is RO if NSACR.CP10 =3D=3D 0, RES0 if the FPU is not p= resent. - * Both are stored in the S bank. - */ - if (env->v7m.secure) { - env->v7m.control[M_REG_S] &=3D ~R_V7M_CONTROL_SFPA_MASK; - env->v7m.control[M_REG_S] |=3D val & R_V7M_CONTROL_SFPA_MA= SK; - } - if (cur_el > 0 && - (env->v7m.secure || !arm_feature(env, ARM_FEATURE_M_SECURI= TY) || - extract32(env->v7m.nsacr, 10, 1))) { - env->v7m.control[M_REG_S] &=3D ~R_V7M_CONTROL_FPCA_MASK; - env->v7m.control[M_REG_S] |=3D val & R_V7M_CONTROL_FPCA_MA= SK; - } - } - break; - default: - bad_reg: - qemu_log_mask(LOG_GUEST_ERROR, "Attempt to write unknown special" - " register %d\n", reg); - return; - } -} - -uint32_t HELPER(v7m_tt)(CPUARMState *env, uint32_t addr, uint32_t op) -{ - /* Implement the TT instruction. op is bits [7:6] of the insn. */ - bool forceunpriv =3D op & 1; - bool alt =3D op & 2; - V8M_SAttributes sattrs =3D {}; - uint32_t tt_resp; - bool r, rw, nsr, nsrw, mrvalid; - int prot; - ARMMMUFaultInfo fi =3D {}; - MemTxAttrs attrs =3D {}; - hwaddr phys_addr; - ARMMMUIdx mmu_idx; - uint32_t mregion; - bool targetpriv; - bool targetsec =3D env->v7m.secure; - bool is_subpage; - - /* - * Work out what the security state and privilege level we're - * interested in is... - */ - if (alt) { - targetsec =3D !targetsec; - } - - if (forceunpriv) { - targetpriv =3D false; - } else { - targetpriv =3D arm_v7m_is_handler_mode(env) || - !(env->v7m.control[targetsec] & R_V7M_CONTROL_NPRIV_MASK); - } - - /* ...and then figure out which MMU index this is */ - mmu_idx =3D arm_v7m_mmu_idx_for_secstate_and_priv(env, targetsec, targ= etpriv); - - /* - * We know that the MPU and SAU don't care about the access type - * for our purposes beyond that we don't want to claim to be - * an insn fetch, so we arbitrarily call this a read. - */ - - /* - * MPU region info only available for privileged or if - * inspecting the other MPU state. - */ - if (arm_current_el(env) !=3D 0 || alt) { - /* We can ignore the return value as prot is always set */ - pmsav8_mpu_lookup(env, addr, MMU_DATA_LOAD, mmu_idx, - &phys_addr, &attrs, &prot, &is_subpage, - &fi, &mregion); - if (mregion =3D=3D -1) { - mrvalid =3D false; - mregion =3D 0; - } else { - mrvalid =3D true; - } - r =3D prot & PAGE_READ; - rw =3D prot & PAGE_WRITE; - } else { - r =3D false; - rw =3D false; - mrvalid =3D false; - mregion =3D 0; - } - - if (env->v7m.secure) { - v8m_security_lookup(env, addr, MMU_DATA_LOAD, mmu_idx, &sattrs); - nsr =3D sattrs.ns && r; - nsrw =3D sattrs.ns && rw; - } else { - sattrs.ns =3D true; - nsr =3D false; - nsrw =3D false; - } - - tt_resp =3D (sattrs.iregion << 24) | - (sattrs.irvalid << 23) | - ((!sattrs.ns) << 22) | - (nsrw << 21) | - (nsr << 20) | - (rw << 19) | - (r << 18) | - (sattrs.srvalid << 17) | - (mrvalid << 16) | - (sattrs.sregion << 8) | - mregion; - - return tt_resp; -} - #endif =20 /* Note that signed overflow is undefined in C. The following routines are @@ -13578,41 +10954,12 @@ int fp_exception_el(CPUARMState *env, int cur_el) return 0; } =20 -ARMMMUIdx arm_v7m_mmu_idx_all(CPUARMState *env, - bool secstate, bool priv, bool negpri) -{ - ARMMMUIdx mmu_idx =3D ARM_MMU_IDX_M; - - if (priv) { - mmu_idx |=3D ARM_MMU_IDX_M_PRIV; - } - - if (negpri) { - mmu_idx |=3D ARM_MMU_IDX_M_NEGPRI; - } - - if (secstate) { - mmu_idx |=3D ARM_MMU_IDX_M_S; - } - - return mmu_idx; -} - -ARMMMUIdx arm_v7m_mmu_idx_for_secstate_and_priv(CPUARMState *env, - bool secstate, bool priv) -{ - bool negpri =3D armv7m_nvic_neg_prio_requested(env->nvic, secstate); - - return arm_v7m_mmu_idx_all(env, secstate, priv, negpri); -} - -/* Return the MMU index for a v7M CPU in the specified security state */ +#ifndef CONFIG_TCG ARMMMUIdx arm_v7m_mmu_idx_for_secstate(CPUARMState *env, bool secstate) { - bool priv =3D arm_current_el(env) !=3D 0; - - return arm_v7m_mmu_idx_for_secstate_and_priv(env, secstate, priv); + g_assert_not_reached(); } +#endif =20 ARMMMUIdx arm_mmu_idx(CPUARMState *env) { diff --git a/target/arm/m_helper.c b/target/arm/m_helper.c new file mode 100644 index 0000000000..1b0ad95a05 --- /dev/null +++ b/target/arm/m_helper.c @@ -0,0 +1,2676 @@ +/* + * ARM generic helpers. + * + * 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/units.h" +#include "target/arm/idau.h" +#include "trace.h" +#include "cpu.h" +#include "internals.h" +#include "exec/gdbstub.h" +#include "exec/helper-proto.h" +#include "qemu/host-utils.h" +#include "sysemu/sysemu.h" +#include "qemu/bitops.h" +#include "qemu/crc32c.h" +#include "qemu/qemu-print.h" +#include "exec/exec-all.h" +#include /* For crc32 */ +#include "hw/semihosting/semihost.h" +#include "sysemu/cpus.h" +#include "sysemu/kvm.h" +#include "qemu/range.h" +#include "qapi/qapi-commands-target.h" +#include "qapi/error.h" +#include "qemu/guest-random.h" +#ifdef CONFIG_TCG +#include "arm_ldst.h" +#include "exec/cpu_ldst.h" +#endif + +#ifdef CONFIG_USER_ONLY + +/* These should probably raise undefined insn exceptions. */ +void HELPER(v7m_msr)(CPUARMState *env, uint32_t reg, uint32_t val) +{ + ARMCPU *cpu =3D env_archcpu(env); + + cpu_abort(CPU(cpu), "v7m_msr %d\n", reg); +} + +uint32_t HELPER(v7m_mrs)(CPUARMState *env, uint32_t reg) +{ + ARMCPU *cpu =3D env_archcpu(env); + + cpu_abort(CPU(cpu), "v7m_mrs %d\n", reg); + return 0; +} + +void HELPER(v7m_bxns)(CPUARMState *env, uint32_t dest) +{ + /* translate.c should never generate calls here in user-only mode */ + g_assert_not_reached(); +} + +void HELPER(v7m_blxns)(CPUARMState *env, uint32_t dest) +{ + /* translate.c should never generate calls here in user-only mode */ + g_assert_not_reached(); +} + +void HELPER(v7m_preserve_fp_state)(CPUARMState *env) +{ + /* translate.c should never generate calls here in user-only mode */ + g_assert_not_reached(); +} + +void HELPER(v7m_vlstm)(CPUARMState *env, uint32_t fptr) +{ + /* translate.c should never generate calls here in user-only mode */ + g_assert_not_reached(); +} + +void HELPER(v7m_vlldm)(CPUARMState *env, uint32_t fptr) +{ + /* translate.c should never generate calls here in user-only mode */ + g_assert_not_reached(); +} + +uint32_t HELPER(v7m_tt)(CPUARMState *env, uint32_t addr, uint32_t op) +{ + /* + * The TT instructions can be used by unprivileged code, but in + * user-only emulation we don't have the MPU. + * Luckily since we know we are NonSecure unprivileged (and that in + * turn means that the A flag wasn't specified), all the bits in the + * register must be zero: + * IREGION: 0 because IRVALID is 0 + * IRVALID: 0 because NS + * S: 0 because NS + * NSRW: 0 because NS + * NSR: 0 because NS + * RW: 0 because unpriv and A flag not set + * R: 0 because unpriv and A flag not set + * SRVALID: 0 because NS + * MRVALID: 0 because unpriv and A flag not set + * SREGION: 0 becaus SRVALID is 0 + * MREGION: 0 because MRVALID is 0 + */ + return 0; +} + +#else + +/* + * What kind of stack write are we doing? This affects how exceptions + * generated during the stacking are treated. + */ +typedef enum StackingMode { + STACK_NORMAL, + STACK_IGNFAULTS, + STACK_LAZYFP, +} StackingMode; + +static bool v7m_stack_write(ARMCPU *cpu, uint32_t addr, uint32_t value, + ARMMMUIdx mmu_idx, StackingMode mode) +{ + CPUState *cs =3D CPU(cpu); + CPUARMState *env =3D &cpu->env; + MemTxAttrs attrs =3D {}; + MemTxResult txres; + target_ulong page_size; + hwaddr physaddr; + int prot; + ARMMMUFaultInfo fi =3D {}; + bool secure =3D mmu_idx & ARM_MMU_IDX_M_S; + int exc; + bool exc_secure; + + if (get_phys_addr(env, addr, MMU_DATA_STORE, mmu_idx, &physaddr, + &attrs, &prot, &page_size, &fi, NULL)) { + /* MPU/SAU lookup failed */ + if (fi.type =3D=3D ARMFault_QEMU_SFault) { + if (mode =3D=3D STACK_LAZYFP) { + qemu_log_mask(CPU_LOG_INT, + "...SecureFault with SFSR.LSPERR " + "during lazy stacking\n"); + env->v7m.sfsr |=3D R_V7M_SFSR_LSPERR_MASK; + } else { + qemu_log_mask(CPU_LOG_INT, + "...SecureFault with SFSR.AUVIOL " + "during stacking\n"); + env->v7m.sfsr |=3D R_V7M_SFSR_AUVIOL_MASK; + } + env->v7m.sfsr |=3D R_V7M_SFSR_SFARVALID_MASK; + env->v7m.sfar =3D addr; + exc =3D ARMV7M_EXCP_SECURE; + exc_secure =3D false; + } else { + if (mode =3D=3D STACK_LAZYFP) { + qemu_log_mask(CPU_LOG_INT, + "...MemManageFault with CFSR.MLSPERR\n"); + env->v7m.cfsr[secure] |=3D R_V7M_CFSR_MLSPERR_MASK; + } else { + qemu_log_mask(CPU_LOG_INT, + "...MemManageFault with CFSR.MSTKERR\n"); + env->v7m.cfsr[secure] |=3D R_V7M_CFSR_MSTKERR_MASK; + } + exc =3D ARMV7M_EXCP_MEM; + exc_secure =3D secure; + } + goto pend_fault; + } + address_space_stl_le(arm_addressspace(cs, attrs), physaddr, value, + attrs, &txres); + if (txres !=3D MEMTX_OK) { + /* BusFault trying to write the data */ + if (mode =3D=3D STACK_LAZYFP) { + qemu_log_mask(CPU_LOG_INT, "...BusFault with BFSR.LSPERR\n"); + env->v7m.cfsr[M_REG_NS] |=3D R_V7M_CFSR_LSPERR_MASK; + } else { + qemu_log_mask(CPU_LOG_INT, "...BusFault with BFSR.STKERR\n"); + env->v7m.cfsr[M_REG_NS] |=3D R_V7M_CFSR_STKERR_MASK; + } + exc =3D ARMV7M_EXCP_BUS; + exc_secure =3D false; + goto pend_fault; + } + return true; + +pend_fault: + /* + * By pending the exception at this point we are making + * the IMPDEF choice "overridden exceptions pended" (see the + * MergeExcInfo() pseudocode). The other choice would be to not + * pend them now and then make a choice about which to throw away + * later if we have two derived exceptions. + * The only case when we must not pend the exception but instead + * throw it away is if we are doing the push of the callee registers + * and we've already generated a derived exception (this is indicated + * by the caller passing STACK_IGNFAULTS). Even in this case we will + * still update the fault status registers. + */ + switch (mode) { + case STACK_NORMAL: + armv7m_nvic_set_pending_derived(env->nvic, exc, exc_secure); + break; + case STACK_LAZYFP: + armv7m_nvic_set_pending_lazyfp(env->nvic, exc, exc_secure); + break; + case STACK_IGNFAULTS: + break; + } + return false; +} + +static bool v7m_stack_read(ARMCPU *cpu, uint32_t *dest, uint32_t addr, + ARMMMUIdx mmu_idx) +{ + CPUState *cs =3D CPU(cpu); + CPUARMState *env =3D &cpu->env; + MemTxAttrs attrs =3D {}; + MemTxResult txres; + target_ulong page_size; + hwaddr physaddr; + int prot; + ARMMMUFaultInfo fi =3D {}; + bool secure =3D mmu_idx & ARM_MMU_IDX_M_S; + int exc; + bool exc_secure; + uint32_t value; + + if (get_phys_addr(env, addr, MMU_DATA_LOAD, mmu_idx, &physaddr, + &attrs, &prot, &page_size, &fi, NULL)) { + /* MPU/SAU lookup failed */ + if (fi.type =3D=3D ARMFault_QEMU_SFault) { + qemu_log_mask(CPU_LOG_INT, + "...SecureFault with SFSR.AUVIOL during unstack\= n"); + env->v7m.sfsr |=3D R_V7M_SFSR_AUVIOL_MASK | R_V7M_SFSR_SFARVAL= ID_MASK; + env->v7m.sfar =3D addr; + exc =3D ARMV7M_EXCP_SECURE; + exc_secure =3D false; + } else { + qemu_log_mask(CPU_LOG_INT, + "...MemManageFault with CFSR.MUNSTKERR\n"); + env->v7m.cfsr[secure] |=3D R_V7M_CFSR_MUNSTKERR_MASK; + exc =3D ARMV7M_EXCP_MEM; + exc_secure =3D secure; + } + goto pend_fault; + } + + value =3D address_space_ldl(arm_addressspace(cs, attrs), physaddr, + attrs, &txres); + if (txres !=3D MEMTX_OK) { + /* BusFault trying to read the data */ + qemu_log_mask(CPU_LOG_INT, "...BusFault with BFSR.UNSTKERR\n"); + env->v7m.cfsr[M_REG_NS] |=3D R_V7M_CFSR_UNSTKERR_MASK; + exc =3D ARMV7M_EXCP_BUS; + exc_secure =3D false; + goto pend_fault; + } + + *dest =3D value; + return true; + +pend_fault: + /* + * By pending the exception at this point we are making + * the IMPDEF choice "overridden exceptions pended" (see the + * MergeExcInfo() pseudocode). The other choice would be to not + * pend them now and then make a choice about which to throw away + * later if we have two derived exceptions. + */ + armv7m_nvic_set_pending(env->nvic, exc, exc_secure); + return false; +} + +void HELPER(v7m_preserve_fp_state)(CPUARMState *env) +{ + /* + * Preserve FP state (because LSPACT was set and we are about + * to execute an FP instruction). This corresponds to the + * PreserveFPState() pseudocode. + * We may throw an exception if the stacking fails. + */ + ARMCPU *cpu =3D env_archcpu(env); + bool is_secure =3D env->v7m.fpccr[M_REG_S] & R_V7M_FPCCR_S_MASK; + bool negpri =3D !(env->v7m.fpccr[M_REG_S] & R_V7M_FPCCR_HFRDY_MASK); + bool is_priv =3D !(env->v7m.fpccr[is_secure] & R_V7M_FPCCR_USER_MASK); + bool splimviol =3D env->v7m.fpccr[is_secure] & R_V7M_FPCCR_SPLIMVIOL_M= ASK; + uint32_t fpcar =3D env->v7m.fpcar[is_secure]; + bool stacked_ok =3D true; + bool ts =3D is_secure && (env->v7m.fpccr[M_REG_S] & R_V7M_FPCCR_TS_MAS= K); + bool take_exception; + + /* Take the iothread lock as we are going to touch the NVIC */ + qemu_mutex_lock_iothread(); + + /* Check the background context had access to the FPU */ + if (!v7m_cpacr_pass(env, is_secure, is_priv)) { + armv7m_nvic_set_pending_lazyfp(env->nvic, ARMV7M_EXCP_USAGE, is_se= cure); + env->v7m.cfsr[is_secure] |=3D R_V7M_CFSR_NOCP_MASK; + stacked_ok =3D false; + } else if (!is_secure && !extract32(env->v7m.nsacr, 10, 1)) { + armv7m_nvic_set_pending_lazyfp(env->nvic, ARMV7M_EXCP_USAGE, M_REG= _S); + env->v7m.cfsr[M_REG_S] |=3D R_V7M_CFSR_NOCP_MASK; + stacked_ok =3D false; + } + + if (!splimviol && stacked_ok) { + /* We only stack if the stack limit wasn't violated */ + int i; + ARMMMUIdx mmu_idx; + + mmu_idx =3D arm_v7m_mmu_idx_all(env, is_secure, is_priv, negpri); + for (i =3D 0; i < (ts ? 32 : 16); i +=3D 2) { + uint64_t dn =3D *aa32_vfp_dreg(env, i / 2); + uint32_t faddr =3D fpcar + 4 * i; + uint32_t slo =3D extract64(dn, 0, 32); + uint32_t shi =3D extract64(dn, 32, 32); + + if (i >=3D 16) { + faddr +=3D 8; /* skip the slot for the FPSCR */ + } + stacked_ok =3D stacked_ok && + v7m_stack_write(cpu, faddr, slo, mmu_idx, STACK_LAZYFP) && + v7m_stack_write(cpu, faddr + 4, shi, mmu_idx, STACK_LAZYFP= ); + } + + stacked_ok =3D stacked_ok && + v7m_stack_write(cpu, fpcar + 0x40, + vfp_get_fpscr(env), mmu_idx, STACK_LAZYFP); + } + + /* + * We definitely pended an exception, but it's possible that it + * might not be able to be taken now. If its priority permits us + * to take it now, then we must not update the LSPACT or FP regs, + * but instead jump out to take the exception immediately. + * If it's just pending and won't be taken until the current + * handler exits, then we do update LSPACT and the FP regs. + */ + take_exception =3D !stacked_ok && + armv7m_nvic_can_take_pending_exception(env->nvic); + + qemu_mutex_unlock_iothread(); + + if (take_exception) { + raise_exception_ra(env, EXCP_LAZYFP, 0, 1, GETPC()); + } + + env->v7m.fpccr[is_secure] &=3D ~R_V7M_FPCCR_LSPACT_MASK; + + if (ts) { + /* Clear s0 to s31 and the FPSCR */ + int i; + + for (i =3D 0; i < 32; i +=3D 2) { + *aa32_vfp_dreg(env, i / 2) =3D 0; + } + vfp_set_fpscr(env, 0); + } + /* + * Otherwise s0 to s15 and FPSCR are UNKNOWN; we choose to leave them + * unchanged. + */ +} + +/* + * Write to v7M CONTROL.SPSEL bit for the specified security bank. + * This may change the current stack pointer between Main and Process + * stack pointers if it is done for the CONTROL register for the current + * security state. + */ +static void write_v7m_control_spsel_for_secstate(CPUARMState *env, + bool new_spsel, + bool secstate) +{ + bool old_is_psp =3D v7m_using_psp(env); + + env->v7m.control[secstate] =3D + deposit32(env->v7m.control[secstate], + R_V7M_CONTROL_SPSEL_SHIFT, + R_V7M_CONTROL_SPSEL_LENGTH, new_spsel); + + if (secstate =3D=3D env->v7m.secure) { + bool new_is_psp =3D v7m_using_psp(env); + uint32_t tmp; + + if (old_is_psp !=3D new_is_psp) { + tmp =3D env->v7m.other_sp; + env->v7m.other_sp =3D env->regs[13]; + env->regs[13] =3D tmp; + } + } +} + +/* + * Write to v7M CONTROL.SPSEL bit. This may change the current + * stack pointer between Main and Process stack pointers. + */ +static void write_v7m_control_spsel(CPUARMState *env, bool new_spsel) +{ + write_v7m_control_spsel_for_secstate(env, new_spsel, env->v7m.secure); +} + +void write_v7m_exception(CPUARMState *env, uint32_t new_exc) +{ + /* + * Write a new value to v7m.exception, thus transitioning into or out + * of Handler mode; this may result in a change of active stack pointe= r. + */ + bool new_is_psp, old_is_psp =3D v7m_using_psp(env); + uint32_t tmp; + + env->v7m.exception =3D new_exc; + + new_is_psp =3D v7m_using_psp(env); + + if (old_is_psp !=3D new_is_psp) { + tmp =3D env->v7m.other_sp; + env->v7m.other_sp =3D env->regs[13]; + env->regs[13] =3D tmp; + } +} + +/* Switch M profile security state between NS and S */ +static void switch_v7m_security_state(CPUARMState *env, bool new_secstate) +{ + uint32_t new_ss_msp, new_ss_psp; + + if (env->v7m.secure =3D=3D new_secstate) { + return; + } + + /* + * All the banked state is accessed by looking at env->v7m.secure + * except for the stack pointer; rearrange the SP appropriately. + */ + new_ss_msp =3D env->v7m.other_ss_msp; + new_ss_psp =3D env->v7m.other_ss_psp; + + if (v7m_using_psp(env)) { + env->v7m.other_ss_psp =3D env->regs[13]; + env->v7m.other_ss_msp =3D env->v7m.other_sp; + } else { + env->v7m.other_ss_msp =3D env->regs[13]; + env->v7m.other_ss_psp =3D env->v7m.other_sp; + } + + env->v7m.secure =3D new_secstate; + + if (v7m_using_psp(env)) { + env->regs[13] =3D new_ss_psp; + env->v7m.other_sp =3D new_ss_msp; + } else { + env->regs[13] =3D new_ss_msp; + env->v7m.other_sp =3D new_ss_psp; + } +} + +void HELPER(v7m_bxns)(CPUARMState *env, uint32_t dest) +{ + /* + * Handle v7M BXNS: + * - if the return value is a magic value, do exception return (like = BX) + * - otherwise bit 0 of the return value is the target security state + */ + uint32_t min_magic; + + if (arm_feature(env, ARM_FEATURE_M_SECURITY)) { + /* Covers FNC_RETURN and EXC_RETURN magic */ + min_magic =3D FNC_RETURN_MIN_MAGIC; + } else { + /* EXC_RETURN magic only */ + min_magic =3D EXC_RETURN_MIN_MAGIC; + } + + if (dest >=3D min_magic) { + /* + * This is an exception return magic value; put it where + * do_v7m_exception_exit() expects and raise EXCEPTION_EXIT. + * Note that if we ever add gen_ss_advance() singlestep support to + * M profile this should count as an "instruction execution comple= te" + * event (compare gen_bx_excret_final_code()). + */ + env->regs[15] =3D dest & ~1; + env->thumb =3D dest & 1; + HELPER(exception_internal)(env, EXCP_EXCEPTION_EXIT); + /* notreached */ + } + + /* translate.c should have made BXNS UNDEF unless we're secure */ + assert(env->v7m.secure); + + if (!(dest & 1)) { + env->v7m.control[M_REG_S] &=3D ~R_V7M_CONTROL_SFPA_MASK; + } + switch_v7m_security_state(env, dest & 1); + env->thumb =3D 1; + env->regs[15] =3D dest & ~1; +} + +void HELPER(v7m_blxns)(CPUARMState *env, uint32_t dest) +{ + /* + * Handle v7M BLXNS: + * - bit 0 of the destination address is the target security state + */ + + /* At this point regs[15] is the address just after the BLXNS */ + uint32_t nextinst =3D env->regs[15] | 1; + uint32_t sp =3D env->regs[13] - 8; + uint32_t saved_psr; + + /* translate.c will have made BLXNS UNDEF unless we're secure */ + assert(env->v7m.secure); + + if (dest & 1) { + /* + * Target is Secure, so this is just a normal BLX, + * except that the low bit doesn't indicate Thumb/not. + */ + env->regs[14] =3D nextinst; + env->thumb =3D 1; + env->regs[15] =3D dest & ~1; + return; + } + + /* Target is non-secure: first push a stack frame */ + if (!QEMU_IS_ALIGNED(sp, 8)) { + qemu_log_mask(LOG_GUEST_ERROR, + "BLXNS with misaligned SP is UNPREDICTABLE\n"); + } + + if (sp < v7m_sp_limit(env)) { + raise_exception(env, EXCP_STKOF, 0, 1); + } + + saved_psr =3D env->v7m.exception; + if (env->v7m.control[M_REG_S] & R_V7M_CONTROL_SFPA_MASK) { + saved_psr |=3D XPSR_SFPA; + } + + /* Note that these stores can throw exceptions on MPU faults */ + cpu_stl_data(env, sp, nextinst); + cpu_stl_data(env, sp + 4, saved_psr); + + env->regs[13] =3D sp; + env->regs[14] =3D 0xfeffffff; + if (arm_v7m_is_handler_mode(env)) { + /* + * Write a dummy value to IPSR, to avoid leaking the current secure + * exception number to non-secure code. This is guaranteed not + * to cause write_v7m_exception() to actually change stacks. + */ + write_v7m_exception(env, 1); + } + env->v7m.control[M_REG_S] &=3D ~R_V7M_CONTROL_SFPA_MASK; + switch_v7m_security_state(env, 0); + env->thumb =3D 1; + env->regs[15] =3D dest; +} + +static uint32_t *get_v7m_sp_ptr(CPUARMState *env, bool secure, bool thread= mode, + bool spsel) +{ + /* + * Return a pointer to the location where we currently store the + * stack pointer for the requested security state and thread mode. + * This pointer will become invalid if the CPU state is updated + * such that the stack pointers are switched around (eg changing + * the SPSEL control bit). + * Compare the v8M ARM ARM pseudocode LookUpSP_with_security_mode(). + * Unlike that pseudocode, we require the caller to pass us in the + * SPSEL control bit value; this is because we also use this + * function in handling of pushing of the callee-saves registers + * part of the v8M stack frame (pseudocode PushCalleeStack()), + * and in the tailchain codepath the SPSEL bit comes from the exception + * return magic LR value from the previous exception. The pseudocode + * opencodes the stack-selection in PushCalleeStack(), but we prefer + * to make this utility function generic enough to do the job. + */ + bool want_psp =3D threadmode && spsel; + + if (secure =3D=3D env->v7m.secure) { + if (want_psp =3D=3D v7m_using_psp(env)) { + return &env->regs[13]; + } else { + return &env->v7m.other_sp; + } + } else { + if (want_psp) { + return &env->v7m.other_ss_psp; + } else { + return &env->v7m.other_ss_msp; + } + } +} + +static bool arm_v7m_load_vector(ARMCPU *cpu, int exc, bool targets_secure, + uint32_t *pvec) +{ + CPUState *cs =3D CPU(cpu); + CPUARMState *env =3D &cpu->env; + MemTxResult result; + uint32_t addr =3D env->v7m.vecbase[targets_secure] + exc * 4; + uint32_t vector_entry; + MemTxAttrs attrs =3D {}; + ARMMMUIdx mmu_idx; + bool exc_secure; + + mmu_idx =3D arm_v7m_mmu_idx_for_secstate_and_priv(env, targets_secure,= true); + + /* + * We don't do a get_phys_addr() here because the rules for vector + * loads are special: they always use the default memory map, and + * the default memory map permits reads from all addresses. + * Since there's no easy way to pass through to pmsav8_mpu_lookup() + * that we want this special case which would always say "yes", + * we just do the SAU lookup here followed by a direct physical load. + */ + attrs.secure =3D targets_secure; + attrs.user =3D false; + + if (arm_feature(env, ARM_FEATURE_M_SECURITY)) { + V8M_SAttributes sattrs =3D {}; + + v8m_security_lookup(env, addr, MMU_DATA_LOAD, mmu_idx, &sattrs); + if (sattrs.ns) { + attrs.secure =3D false; + } else if (!targets_secure) { + /* NS access to S memory */ + goto load_fail; + } + } + + vector_entry =3D address_space_ldl(arm_addressspace(cs, attrs), addr, + attrs, &result); + if (result !=3D MEMTX_OK) { + goto load_fail; + } + *pvec =3D vector_entry; + return true; + +load_fail: + /* + * All vector table fetch fails are reported as HardFault, with + * HFSR.VECTTBL and .FORCED set. (FORCED is set because + * technically the underlying exception is a MemManage or BusFault + * that is escalated to HardFault.) This is a terminal exception, + * so we will either take the HardFault immediately or else enter + * lockup (the latter case is handled in armv7m_nvic_set_pending_deriv= ed()). + */ + exc_secure =3D targets_secure || + !(cpu->env.v7m.aircr & R_V7M_AIRCR_BFHFNMINS_MASK); + env->v7m.hfsr |=3D R_V7M_HFSR_VECTTBL_MASK | R_V7M_HFSR_FORCED_MASK; + armv7m_nvic_set_pending_derived(env->nvic, ARMV7M_EXCP_HARD, exc_secur= e); + return false; +} + +static uint32_t v7m_integrity_sig(CPUARMState *env, uint32_t lr) +{ + /* + * Return the integrity signature value for the callee-saves + * stack frame section. @lr is the exception return payload/LR value + * whose FType bit forms bit 0 of the signature if FP is present. + */ + uint32_t sig =3D 0xfefa125a; + + if (!arm_feature(env, ARM_FEATURE_VFP) || (lr & R_V7M_EXCRET_FTYPE_MAS= K)) { + sig |=3D 1; + } + return sig; +} + +static bool v7m_push_callee_stack(ARMCPU *cpu, uint32_t lr, bool dotailcha= in, + bool ignore_faults) +{ + /* + * For v8M, push the callee-saves register part of the stack frame. + * Compare the v8M pseudocode PushCalleeStack(). + * In the tailchaining case this may not be the current stack. + */ + CPUARMState *env =3D &cpu->env; + uint32_t *frame_sp_p; + uint32_t frameptr; + ARMMMUIdx mmu_idx; + bool stacked_ok; + uint32_t limit; + bool want_psp; + uint32_t sig; + StackingMode smode =3D ignore_faults ? STACK_IGNFAULTS : STACK_NORMAL; + + if (dotailchain) { + bool mode =3D lr & R_V7M_EXCRET_MODE_MASK; + bool priv =3D !(env->v7m.control[M_REG_S] & R_V7M_CONTROL_NPRIV_MA= SK) || + !mode; + + mmu_idx =3D arm_v7m_mmu_idx_for_secstate_and_priv(env, M_REG_S, pr= iv); + frame_sp_p =3D get_v7m_sp_ptr(env, M_REG_S, mode, + lr & R_V7M_EXCRET_SPSEL_MASK); + want_psp =3D mode && (lr & R_V7M_EXCRET_SPSEL_MASK); + if (want_psp) { + limit =3D env->v7m.psplim[M_REG_S]; + } else { + limit =3D env->v7m.msplim[M_REG_S]; + } + } else { + mmu_idx =3D arm_mmu_idx(env); + frame_sp_p =3D &env->regs[13]; + limit =3D v7m_sp_limit(env); + } + + frameptr =3D *frame_sp_p - 0x28; + if (frameptr < limit) { + /* + * Stack limit failure: set SP to the limit value, and generate + * STKOF UsageFault. Stack pushes below the limit must not be + * performed. It is IMPDEF whether pushes above the limit are + * performed; we choose not to. + */ + qemu_log_mask(CPU_LOG_INT, + "...STKOF during callee-saves register stacking\n"); + env->v7m.cfsr[env->v7m.secure] |=3D R_V7M_CFSR_STKOF_MASK; + armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_USAGE, + env->v7m.secure); + *frame_sp_p =3D limit; + return true; + } + + /* + * Write as much of the stack frame as we can. A write failure may + * cause us to pend a derived exception. + */ + sig =3D v7m_integrity_sig(env, lr); + stacked_ok =3D + v7m_stack_write(cpu, frameptr, sig, mmu_idx, smode) && + v7m_stack_write(cpu, frameptr + 0x8, env->regs[4], mmu_idx, smode)= && + v7m_stack_write(cpu, frameptr + 0xc, env->regs[5], mmu_idx, smode)= && + v7m_stack_write(cpu, frameptr + 0x10, env->regs[6], mmu_idx, smode= ) && + v7m_stack_write(cpu, frameptr + 0x14, env->regs[7], mmu_idx, smode= ) && + v7m_stack_write(cpu, frameptr + 0x18, env->regs[8], mmu_idx, smode= ) && + v7m_stack_write(cpu, frameptr + 0x1c, env->regs[9], mmu_idx, smode= ) && + v7m_stack_write(cpu, frameptr + 0x20, env->regs[10], mmu_idx, smod= e) && + v7m_stack_write(cpu, frameptr + 0x24, env->regs[11], mmu_idx, smod= e); + + /* Update SP regardless of whether any of the stack accesses failed. */ + *frame_sp_p =3D frameptr; + + return !stacked_ok; +} + +static void v7m_exception_taken(ARMCPU *cpu, uint32_t lr, bool dotailchain, + bool ignore_stackfaults) +{ + /* + * Do the "take the exception" parts of exception entry, + * but not the pushing of state to the stack. This is + * similar to the pseudocode ExceptionTaken() function. + */ + CPUARMState *env =3D &cpu->env; + uint32_t addr; + bool targets_secure; + int exc; + bool push_failed =3D false; + + armv7m_nvic_get_pending_irq_info(env->nvic, &exc, &targets_secure); + qemu_log_mask(CPU_LOG_INT, "...taking pending %s exception %d\n", + targets_secure ? "secure" : "nonsecure", exc); + + if (dotailchain) { + /* Sanitize LR FType and PREFIX bits */ + if (!arm_feature(env, ARM_FEATURE_VFP)) { + lr |=3D R_V7M_EXCRET_FTYPE_MASK; + } + lr =3D deposit32(lr, 24, 8, 0xff); + } + + if (arm_feature(env, ARM_FEATURE_V8)) { + if (arm_feature(env, ARM_FEATURE_M_SECURITY) && + (lr & R_V7M_EXCRET_S_MASK)) { + /* + * The background code (the owner of the registers in the + * exception frame) is Secure. This means it may either already + * have or now needs to push callee-saves registers. + */ + if (targets_secure) { + if (dotailchain && !(lr & R_V7M_EXCRET_ES_MASK)) { + /* + * We took an exception from Secure to NonSecure + * (which means the callee-saved registers got stacked) + * and are now tailchaining to a Secure exception. + * Clear DCRS so eventual return from this Secure + * exception unstacks the callee-saved registers. + */ + lr &=3D ~R_V7M_EXCRET_DCRS_MASK; + } + } else { + /* + * We're going to a non-secure exception; push the + * callee-saves registers to the stack now, if they're + * not already saved. + */ + if (lr & R_V7M_EXCRET_DCRS_MASK && + !(dotailchain && !(lr & R_V7M_EXCRET_ES_MASK))) { + push_failed =3D v7m_push_callee_stack(cpu, lr, dotailc= hain, + ignore_stackfaults= ); + } + lr |=3D R_V7M_EXCRET_DCRS_MASK; + } + } + + lr &=3D ~R_V7M_EXCRET_ES_MASK; + if (targets_secure || !arm_feature(env, ARM_FEATURE_M_SECURITY)) { + lr |=3D R_V7M_EXCRET_ES_MASK; + } + lr &=3D ~R_V7M_EXCRET_SPSEL_MASK; + if (env->v7m.control[targets_secure] & R_V7M_CONTROL_SPSEL_MASK) { + lr |=3D R_V7M_EXCRET_SPSEL_MASK; + } + + /* + * Clear registers if necessary to prevent non-secure exception + * code being able to see register values from secure code. + * Where register values become architecturally UNKNOWN we leave + * them with their previous values. + */ + if (arm_feature(env, ARM_FEATURE_M_SECURITY)) { + if (!targets_secure) { + /* + * Always clear the caller-saved registers (they have been + * pushed to the stack earlier in v7m_push_stack()). + * Clear callee-saved registers if the background code is + * Secure (in which case these regs were saved in + * v7m_push_callee_stack()). + */ + int i; + + for (i =3D 0; i < 13; i++) { + /* r4..r11 are callee-saves, zero only if EXCRET.S =3D= =3D 1 */ + if (i < 4 || i > 11 || (lr & R_V7M_EXCRET_S_MASK)) { + env->regs[i] =3D 0; + } + } + /* Clear EAPSR */ + xpsr_write(env, 0, XPSR_NZCV | XPSR_Q | XPSR_GE | XPSR_IT); + } + } + } + + if (push_failed && !ignore_stackfaults) { + /* + * Derived exception on callee-saves register stacking: + * we might now want to take a different exception which + * targets a different security state, so try again from the top. + */ + qemu_log_mask(CPU_LOG_INT, + "...derived exception on callee-saves register stack= ing"); + v7m_exception_taken(cpu, lr, true, true); + return; + } + + if (!arm_v7m_load_vector(cpu, exc, targets_secure, &addr)) { + /* Vector load failed: derived exception */ + qemu_log_mask(CPU_LOG_INT, "...derived exception on vector table l= oad"); + v7m_exception_taken(cpu, lr, true, true); + return; + } + + /* + * Now we've done everything that might cause a derived exception + * we can go ahead and activate whichever exception we're going to + * take (which might now be the derived exception). + */ + armv7m_nvic_acknowledge_irq(env->nvic); + + /* Switch to target security state -- must do this before writing SPSE= L */ + switch_v7m_security_state(env, targets_secure); + write_v7m_control_spsel(env, 0); + arm_clear_exclusive(env); + /* Clear SFPA and FPCA (has no effect if no FPU) */ + env->v7m.control[M_REG_S] &=3D + ~(R_V7M_CONTROL_FPCA_MASK | R_V7M_CONTROL_SFPA_MASK); + /* Clear IT bits */ + env->condexec_bits =3D 0; + env->regs[14] =3D lr; + env->regs[15] =3D addr & 0xfffffffe; + env->thumb =3D addr & 1; +} + +static void v7m_update_fpccr(CPUARMState *env, uint32_t frameptr, + bool apply_splim) +{ + /* + * Like the pseudocode UpdateFPCCR: save state in FPCAR and FPCCR + * that we will need later in order to do lazy FP reg stacking. + */ + bool is_secure =3D env->v7m.secure; + void *nvic =3D env->nvic; + /* + * Some bits are unbanked and live always in fpccr[M_REG_S]; some bits + * are banked and we want to update the bit in the bank for the + * current security state; and in one case we want to specifically + * update the NS banked version of a bit even if we are secure. + */ + uint32_t *fpccr_s =3D &env->v7m.fpccr[M_REG_S]; + uint32_t *fpccr_ns =3D &env->v7m.fpccr[M_REG_NS]; + uint32_t *fpccr =3D &env->v7m.fpccr[is_secure]; + bool hfrdy, bfrdy, mmrdy, ns_ufrdy, s_ufrdy, sfrdy, monrdy; + + env->v7m.fpcar[is_secure] =3D frameptr & ~0x7; + + if (apply_splim && arm_feature(env, ARM_FEATURE_V8)) { + bool splimviol; + uint32_t splim =3D v7m_sp_limit(env); + bool ign =3D armv7m_nvic_neg_prio_requested(nvic, is_secure) && + (env->v7m.ccr[is_secure] & R_V7M_CCR_STKOFHFNMIGN_MASK); + + splimviol =3D !ign && frameptr < splim; + *fpccr =3D FIELD_DP32(*fpccr, V7M_FPCCR, SPLIMVIOL, splimviol); + } + + *fpccr =3D FIELD_DP32(*fpccr, V7M_FPCCR, LSPACT, 1); + + *fpccr_s =3D FIELD_DP32(*fpccr_s, V7M_FPCCR, S, is_secure); + + *fpccr =3D FIELD_DP32(*fpccr, V7M_FPCCR, USER, arm_current_el(env) =3D= =3D 0); + + *fpccr =3D FIELD_DP32(*fpccr, V7M_FPCCR, THREAD, + !arm_v7m_is_handler_mode(env)); + + hfrdy =3D armv7m_nvic_get_ready_status(nvic, ARMV7M_EXCP_HARD, false); + *fpccr_s =3D FIELD_DP32(*fpccr_s, V7M_FPCCR, HFRDY, hfrdy); + + bfrdy =3D armv7m_nvic_get_ready_status(nvic, ARMV7M_EXCP_BUS, false); + *fpccr_s =3D FIELD_DP32(*fpccr_s, V7M_FPCCR, BFRDY, bfrdy); + + mmrdy =3D armv7m_nvic_get_ready_status(nvic, ARMV7M_EXCP_MEM, is_secur= e); + *fpccr =3D FIELD_DP32(*fpccr, V7M_FPCCR, MMRDY, mmrdy); + + ns_ufrdy =3D armv7m_nvic_get_ready_status(nvic, ARMV7M_EXCP_USAGE, fal= se); + *fpccr_ns =3D FIELD_DP32(*fpccr_ns, V7M_FPCCR, UFRDY, ns_ufrdy); + + monrdy =3D armv7m_nvic_get_ready_status(nvic, ARMV7M_EXCP_DEBUG, false= ); + *fpccr_s =3D FIELD_DP32(*fpccr_s, V7M_FPCCR, MONRDY, monrdy); + + if (arm_feature(env, ARM_FEATURE_M_SECURITY)) { + s_ufrdy =3D armv7m_nvic_get_ready_status(nvic, ARMV7M_EXCP_USAGE, = true); + *fpccr_s =3D FIELD_DP32(*fpccr_s, V7M_FPCCR, UFRDY, s_ufrdy); + + sfrdy =3D armv7m_nvic_get_ready_status(nvic, ARMV7M_EXCP_SECURE, f= alse); + *fpccr_s =3D FIELD_DP32(*fpccr_s, V7M_FPCCR, SFRDY, sfrdy); + } +} + +void HELPER(v7m_vlstm)(CPUARMState *env, uint32_t fptr) +{ + /* fptr is the value of Rn, the frame pointer we store the FP regs to = */ + bool s =3D env->v7m.fpccr[M_REG_S] & R_V7M_FPCCR_S_MASK; + bool lspact =3D env->v7m.fpccr[s] & R_V7M_FPCCR_LSPACT_MASK; + + assert(env->v7m.secure); + + if (!(env->v7m.control[M_REG_S] & R_V7M_CONTROL_SFPA_MASK)) { + return; + } + + /* Check access to the coprocessor is permitted */ + if (!v7m_cpacr_pass(env, true, arm_current_el(env) !=3D 0)) { + raise_exception_ra(env, EXCP_NOCP, 0, 1, GETPC()); + } + + if (lspact) { + /* LSPACT should not be active when there is active FP state */ + raise_exception_ra(env, EXCP_LSERR, 0, 1, GETPC()); + } + + if (fptr & 7) { + raise_exception_ra(env, EXCP_UNALIGNED, 0, 1, GETPC()); + } + + /* + * Note that we do not use v7m_stack_write() here, because the + * accesses should not set the FSR bits for stacking errors if they + * fail. (In pseudocode terms, they are AccType_NORMAL, not AccType_ST= ACK + * or AccType_LAZYFP). Faults in cpu_stl_data() will throw exceptions + * and longjmp out. + */ + if (!(env->v7m.fpccr[M_REG_S] & R_V7M_FPCCR_LSPEN_MASK)) { + bool ts =3D env->v7m.fpccr[M_REG_S] & R_V7M_FPCCR_TS_MASK; + int i; + + for (i =3D 0; i < (ts ? 32 : 16); i +=3D 2) { + uint64_t dn =3D *aa32_vfp_dreg(env, i / 2); + uint32_t faddr =3D fptr + 4 * i; + uint32_t slo =3D extract64(dn, 0, 32); + uint32_t shi =3D extract64(dn, 32, 32); + + if (i >=3D 16) { + faddr +=3D 8; /* skip the slot for the FPSCR */ + } + cpu_stl_data(env, faddr, slo); + cpu_stl_data(env, faddr + 4, shi); + } + cpu_stl_data(env, fptr + 0x40, vfp_get_fpscr(env)); + + /* + * If TS is 0 then s0 to s15 and FPSCR are UNKNOWN; we choose to + * leave them unchanged, matching our choice in v7m_preserve_fp_st= ate. + */ + if (ts) { + for (i =3D 0; i < 32; i +=3D 2) { + *aa32_vfp_dreg(env, i / 2) =3D 0; + } + vfp_set_fpscr(env, 0); + } + } else { + v7m_update_fpccr(env, fptr, false); + } + + env->v7m.control[M_REG_S] &=3D ~R_V7M_CONTROL_FPCA_MASK; +} + +void HELPER(v7m_vlldm)(CPUARMState *env, uint32_t fptr) +{ + /* fptr is the value of Rn, the frame pointer we load the FP regs from= */ + assert(env->v7m.secure); + + if (!(env->v7m.control[M_REG_S] & R_V7M_CONTROL_SFPA_MASK)) { + return; + } + + /* Check access to the coprocessor is permitted */ + if (!v7m_cpacr_pass(env, true, arm_current_el(env) !=3D 0)) { + raise_exception_ra(env, EXCP_NOCP, 0, 1, GETPC()); + } + + if (env->v7m.fpccr[M_REG_S] & R_V7M_FPCCR_LSPACT_MASK) { + /* State in FP is still valid */ + env->v7m.fpccr[M_REG_S] &=3D ~R_V7M_FPCCR_LSPACT_MASK; + } else { + bool ts =3D env->v7m.fpccr[M_REG_S] & R_V7M_FPCCR_TS_MASK; + int i; + uint32_t fpscr; + + if (fptr & 7) { + raise_exception_ra(env, EXCP_UNALIGNED, 0, 1, GETPC()); + } + + for (i =3D 0; i < (ts ? 32 : 16); i +=3D 2) { + uint32_t slo, shi; + uint64_t dn; + uint32_t faddr =3D fptr + 4 * i; + + if (i >=3D 16) { + faddr +=3D 8; /* skip the slot for the FPSCR */ + } + + slo =3D cpu_ldl_data(env, faddr); + shi =3D cpu_ldl_data(env, faddr + 4); + + dn =3D (uint64_t) shi << 32 | slo; + *aa32_vfp_dreg(env, i / 2) =3D dn; + } + fpscr =3D cpu_ldl_data(env, fptr + 0x40); + vfp_set_fpscr(env, fpscr); + } + + env->v7m.control[M_REG_S] |=3D R_V7M_CONTROL_FPCA_MASK; +} + +static bool v7m_push_stack(ARMCPU *cpu) +{ + /* + * Do the "set up stack frame" part of exception entry, + * similar to pseudocode PushStack(). + * Return true if we generate a derived exception (and so + * should ignore further stack faults trying to process + * that derived exception.) + */ + bool stacked_ok =3D true, limitviol =3D false; + CPUARMState *env =3D &cpu->env; + uint32_t xpsr =3D xpsr_read(env); + uint32_t frameptr =3D env->regs[13]; + ARMMMUIdx mmu_idx =3D arm_mmu_idx(env); + uint32_t framesize; + bool nsacr_cp10 =3D extract32(env->v7m.nsacr, 10, 1); + + if ((env->v7m.control[M_REG_S] & R_V7M_CONTROL_FPCA_MASK) && + (env->v7m.secure || nsacr_cp10)) { + if (env->v7m.secure && + env->v7m.fpccr[M_REG_S] & R_V7M_FPCCR_TS_MASK) { + framesize =3D 0xa8; + } else { + framesize =3D 0x68; + } + } else { + framesize =3D 0x20; + } + + /* Align stack pointer if the guest wants that */ + if ((frameptr & 4) && + (env->v7m.ccr[env->v7m.secure] & R_V7M_CCR_STKALIGN_MASK)) { + frameptr -=3D 4; + xpsr |=3D XPSR_SPREALIGN; + } + + xpsr &=3D ~XPSR_SFPA; + if (env->v7m.secure && + (env->v7m.control[M_REG_S] & R_V7M_CONTROL_SFPA_MASK)) { + xpsr |=3D XPSR_SFPA; + } + + frameptr -=3D framesize; + + if (arm_feature(env, ARM_FEATURE_V8)) { + uint32_t limit =3D v7m_sp_limit(env); + + if (frameptr < limit) { + /* + * Stack limit failure: set SP to the limit value, and generate + * STKOF UsageFault. Stack pushes below the limit must not be + * performed. It is IMPDEF whether pushes above the limit are + * performed; we choose not to. + */ + qemu_log_mask(CPU_LOG_INT, + "...STKOF during stacking\n"); + env->v7m.cfsr[env->v7m.secure] |=3D R_V7M_CFSR_STKOF_MASK; + armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_USAGE, + env->v7m.secure); + env->regs[13] =3D limit; + /* + * We won't try to perform any further memory accesses but + * we must continue through the following code to check for + * permission faults during FPU state preservation, and we + * must update FPCCR if lazy stacking is enabled. + */ + limitviol =3D true; + stacked_ok =3D false; + } + } + + /* + * Write as much of the stack frame as we can. If we fail a stack + * write this will result in a derived exception being pended + * (which may be taken in preference to the one we started with + * if it has higher priority). + */ + stacked_ok =3D stacked_ok && + v7m_stack_write(cpu, frameptr, env->regs[0], mmu_idx, STACK_NORMAL= ) && + v7m_stack_write(cpu, frameptr + 4, env->regs[1], + mmu_idx, STACK_NORMAL) && + v7m_stack_write(cpu, frameptr + 8, env->regs[2], + mmu_idx, STACK_NORMAL) && + v7m_stack_write(cpu, frameptr + 12, env->regs[3], + mmu_idx, STACK_NORMAL) && + v7m_stack_write(cpu, frameptr + 16, env->regs[12], + mmu_idx, STACK_NORMAL) && + v7m_stack_write(cpu, frameptr + 20, env->regs[14], + mmu_idx, STACK_NORMAL) && + v7m_stack_write(cpu, frameptr + 24, env->regs[15], + mmu_idx, STACK_NORMAL) && + v7m_stack_write(cpu, frameptr + 28, xpsr, mmu_idx, STACK_NORMAL); + + if (env->v7m.control[M_REG_S] & R_V7M_CONTROL_FPCA_MASK) { + /* FPU is active, try to save its registers */ + bool fpccr_s =3D env->v7m.fpccr[M_REG_S] & R_V7M_FPCCR_S_MASK; + bool lspact =3D env->v7m.fpccr[fpccr_s] & R_V7M_FPCCR_LSPACT_MASK; + + if (lspact && arm_feature(env, ARM_FEATURE_M_SECURITY)) { + qemu_log_mask(CPU_LOG_INT, + "...SecureFault because LSPACT and FPCA both set= \n"); + env->v7m.sfsr |=3D R_V7M_SFSR_LSERR_MASK; + armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_SECURE, false); + } else if (!env->v7m.secure && !nsacr_cp10) { + qemu_log_mask(CPU_LOG_INT, + "...Secure UsageFault with CFSR.NOCP because " + "NSACR.CP10 prevents stacking FP regs\n"); + armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_USAGE, M_REG_S); + env->v7m.cfsr[M_REG_S] |=3D R_V7M_CFSR_NOCP_MASK; + } else { + if (!(env->v7m.fpccr[M_REG_S] & R_V7M_FPCCR_LSPEN_MASK)) { + /* Lazy stacking disabled, save registers now */ + int i; + bool cpacr_pass =3D v7m_cpacr_pass(env, env->v7m.secure, + arm_current_el(env) !=3D = 0); + + if (stacked_ok && !cpacr_pass) { + /* + * Take UsageFault if CPACR forbids access. The pseudo= code + * here does a full CheckCPEnabled() but we know the N= SACR + * check can never fail as we have already handled tha= t. + */ + qemu_log_mask(CPU_LOG_INT, + "...UsageFault with CFSR.NOCP because " + "CPACR.CP10 prevents stacking FP regs\n"= ); + armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_USAGE, + env->v7m.secure); + env->v7m.cfsr[env->v7m.secure] |=3D R_V7M_CFSR_NOCP_MA= SK; + stacked_ok =3D false; + } + + for (i =3D 0; i < ((framesize =3D=3D 0xa8) ? 32 : 16); i += =3D 2) { + uint64_t dn =3D *aa32_vfp_dreg(env, i / 2); + uint32_t faddr =3D frameptr + 0x20 + 4 * i; + uint32_t slo =3D extract64(dn, 0, 32); + uint32_t shi =3D extract64(dn, 32, 32); + + if (i >=3D 16) { + faddr +=3D 8; /* skip the slot for the FPSCR */ + } + stacked_ok =3D stacked_ok && + v7m_stack_write(cpu, faddr, slo, + mmu_idx, STACK_NORMAL) && + v7m_stack_write(cpu, faddr + 4, shi, + mmu_idx, STACK_NORMAL); + } + stacked_ok =3D stacked_ok && + v7m_stack_write(cpu, frameptr + 0x60, + vfp_get_fpscr(env), mmu_idx, STACK_NOR= MAL); + if (cpacr_pass) { + for (i =3D 0; i < ((framesize =3D=3D 0xa8) ? 32 : 16);= i +=3D 2) { + *aa32_vfp_dreg(env, i / 2) =3D 0; + } + vfp_set_fpscr(env, 0); + } + } else { + /* Lazy stacking enabled, save necessary info to stack lat= er */ + v7m_update_fpccr(env, frameptr + 0x20, true); + } + } + } + + /* + * If we broke a stack limit then SP was already updated earlier; + * otherwise we update SP regardless of whether any of the stack + * accesses failed or we took some other kind of fault. + */ + if (!limitviol) { + env->regs[13] =3D frameptr; + } + + return !stacked_ok; +} + +static void do_v7m_exception_exit(ARMCPU *cpu) +{ + CPUARMState *env =3D &cpu->env; + uint32_t excret; + uint32_t xpsr, xpsr_mask; + bool ufault =3D false; + bool sfault =3D false; + bool return_to_sp_process; + bool return_to_handler; + bool rettobase =3D false; + bool exc_secure =3D false; + bool return_to_secure; + bool ftype; + bool restore_s16_s31; + + /* + * If we're not in Handler mode then jumps to magic exception-exit + * addresses don't have magic behaviour. However for the v8M + * security extensions the magic secure-function-return has to + * work in thread mode too, so to avoid doing an extra check in + * the generated code we allow exception-exit magic to also cause the + * internal exception and bring us here in thread mode. Correct code + * will never try to do this (the following insn fetch will always + * fault) so we the overhead of having taken an unnecessary exception + * doesn't matter. + */ + if (!arm_v7m_is_handler_mode(env)) { + return; + } + + /* + * In the spec pseudocode ExceptionReturn() is called directly + * from BXWritePC() and gets the full target PC value including + * bit zero. In QEMU's implementation we treat it as a normal + * jump-to-register (which is then caught later on), and so split + * the target value up between env->regs[15] and env->thumb in + * gen_bx(). Reconstitute it. + */ + excret =3D env->regs[15]; + if (env->thumb) { + excret |=3D 1; + } + + qemu_log_mask(CPU_LOG_INT, "Exception return: magic PC %" PRIx32 + " previous exception %d\n", + excret, env->v7m.exception); + + if ((excret & R_V7M_EXCRET_RES1_MASK) !=3D R_V7M_EXCRET_RES1_MASK) { + qemu_log_mask(LOG_GUEST_ERROR, "M profile: zero high bits in excep= tion " + "exit PC value 0x%" PRIx32 " are UNPREDICTABLE\n", + excret); + } + + ftype =3D excret & R_V7M_EXCRET_FTYPE_MASK; + + if (!arm_feature(env, ARM_FEATURE_VFP) && !ftype) { + qemu_log_mask(LOG_GUEST_ERROR, "M profile: zero FTYPE in exception= " + "exit PC value 0x%" PRIx32 " is UNPREDICTABLE " + "if FPU not present\n", + excret); + ftype =3D true; + } + + if (arm_feature(env, ARM_FEATURE_M_SECURITY)) { + /* + * EXC_RETURN.ES validation check (R_SMFL). We must do this before + * we pick which FAULTMASK to clear. + */ + if (!env->v7m.secure && + ((excret & R_V7M_EXCRET_ES_MASK) || + !(excret & R_V7M_EXCRET_DCRS_MASK))) { + sfault =3D 1; + /* For all other purposes, treat ES as 0 (R_HXSR) */ + excret &=3D ~R_V7M_EXCRET_ES_MASK; + } + exc_secure =3D excret & R_V7M_EXCRET_ES_MASK; + } + + if (env->v7m.exception !=3D ARMV7M_EXCP_NMI) { + /* + * Auto-clear FAULTMASK on return from other than NMI. + * If the security extension is implemented then this only + * happens if the raw execution priority is >=3D 0; the + * value of the ES bit in the exception return value indicates + * which security state's faultmask to clear. (v8M ARM ARM R_KBNF.) + */ + if (arm_feature(env, ARM_FEATURE_M_SECURITY)) { + if (armv7m_nvic_raw_execution_priority(env->nvic) >=3D 0) { + env->v7m.faultmask[exc_secure] =3D 0; + } + } else { + env->v7m.faultmask[M_REG_NS] =3D 0; + } + } + + switch (armv7m_nvic_complete_irq(env->nvic, env->v7m.exception, + exc_secure)) { + case -1: + /* attempt to exit an exception that isn't active */ + ufault =3D true; + break; + case 0: + /* still an irq active now */ + break; + case 1: + /* + * We returned to base exception level, no nesting. + * (In the pseudocode this is written using "NestedActivation !=3D= 1" + * where we have 'rettobase =3D=3D false'.) + */ + rettobase =3D true; + break; + default: + g_assert_not_reached(); + } + + return_to_handler =3D !(excret & R_V7M_EXCRET_MODE_MASK); + return_to_sp_process =3D excret & R_V7M_EXCRET_SPSEL_MASK; + return_to_secure =3D arm_feature(env, ARM_FEATURE_M_SECURITY) && + (excret & R_V7M_EXCRET_S_MASK); + + if (arm_feature(env, ARM_FEATURE_V8)) { + if (!arm_feature(env, ARM_FEATURE_M_SECURITY)) { + /* + * UNPREDICTABLE if S =3D=3D 1 or DCRS =3D=3D 0 or ES =3D=3D 1= (R_XLCP); + * we choose to take the UsageFault. + */ + if ((excret & R_V7M_EXCRET_S_MASK) || + (excret & R_V7M_EXCRET_ES_MASK) || + !(excret & R_V7M_EXCRET_DCRS_MASK)) { + ufault =3D true; + } + } + if (excret & R_V7M_EXCRET_RES0_MASK) { + ufault =3D true; + } + } else { + /* For v7M we only recognize certain combinations of the low bits = */ + switch (excret & 0xf) { + case 1: /* Return to Handler */ + break; + case 13: /* Return to Thread using Process stack */ + case 9: /* Return to Thread using Main stack */ + /* + * We only need to check NONBASETHRDENA for v7M, because in + * v8M this bit does not exist (it is RES1). + */ + if (!rettobase && + !(env->v7m.ccr[env->v7m.secure] & + R_V7M_CCR_NONBASETHRDENA_MASK)) { + ufault =3D true; + } + break; + default: + ufault =3D true; + } + } + + /* + * Set CONTROL.SPSEL from excret.SPSEL. Since we're still in + * Handler mode (and will be until we write the new XPSR.Interrupt + * field) this does not switch around the current stack pointer. + * We must do this before we do any kind of tailchaining, including + * for the derived exceptions on integrity check failures, or we will + * give the guest an incorrect EXCRET.SPSEL value on exception entry. + */ + write_v7m_control_spsel_for_secstate(env, return_to_sp_process, exc_se= cure); + + /* + * Clear scratch FP values left in caller saved registers; this + * must happen before any kind of tail chaining. + */ + if ((env->v7m.fpccr[M_REG_S] & R_V7M_FPCCR_CLRONRET_MASK) && + (env->v7m.control[M_REG_S] & R_V7M_CONTROL_FPCA_MASK)) { + if (env->v7m.fpccr[M_REG_S] & R_V7M_FPCCR_LSPACT_MASK) { + env->v7m.sfsr |=3D R_V7M_SFSR_LSERR_MASK; + armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_SECURE, false); + qemu_log_mask(CPU_LOG_INT, "...taking SecureFault on existing " + "stackframe: error during lazy state deactivatio= n\n"); + v7m_exception_taken(cpu, excret, true, false); + return; + } else { + /* Clear s0..s15 and FPSCR */ + int i; + + for (i =3D 0; i < 16; i +=3D 2) { + *aa32_vfp_dreg(env, i / 2) =3D 0; + } + vfp_set_fpscr(env, 0); + } + } + + if (sfault) { + env->v7m.sfsr |=3D R_V7M_SFSR_INVER_MASK; + armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_SECURE, false); + qemu_log_mask(CPU_LOG_INT, "...taking SecureFault on existing " + "stackframe: failed EXC_RETURN.ES validity check\n"); + v7m_exception_taken(cpu, excret, true, false); + return; + } + + if (ufault) { + /* + * Bad exception return: instead of popping the exception + * stack, directly take a usage fault on the current stack. + */ + env->v7m.cfsr[env->v7m.secure] |=3D R_V7M_CFSR_INVPC_MASK; + armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_USAGE, env->v7m.sec= ure); + qemu_log_mask(CPU_LOG_INT, "...taking UsageFault on existing " + "stackframe: failed exception return integrity check= \n"); + v7m_exception_taken(cpu, excret, true, false); + return; + } + + /* + * Tailchaining: if there is currently a pending exception that + * is high enough priority to preempt execution at the level we're + * about to return to, then just directly take that exception now, + * avoiding an unstack-and-then-stack. Note that now we have + * deactivated the previous exception by calling armv7m_nvic_complete_= irq() + * our current execution priority is already the execution priority we= are + * returning to -- none of the state we would unstack or set based on + * the EXCRET value affects it. + */ + if (armv7m_nvic_can_take_pending_exception(env->nvic)) { + qemu_log_mask(CPU_LOG_INT, "...tailchaining to pending exception\n= "); + v7m_exception_taken(cpu, excret, true, false); + return; + } + + switch_v7m_security_state(env, return_to_secure); + + { + /* + * The stack pointer we should be reading the exception frame from + * depends on bits in the magic exception return type value (and + * for v8M isn't necessarily the stack pointer we will eventually + * end up resuming execution with). Get a pointer to the location + * in the CPU state struct where the SP we need is currently being + * stored; we will use and modify it in place. + * We use this limited C variable scope so we don't accidentally + * use 'frame_sp_p' after we do something that makes it invalid. + */ + uint32_t *frame_sp_p =3D get_v7m_sp_ptr(env, + return_to_secure, + !return_to_handler, + return_to_sp_process); + uint32_t frameptr =3D *frame_sp_p; + bool pop_ok =3D true; + ARMMMUIdx mmu_idx; + bool return_to_priv =3D return_to_handler || + !(env->v7m.control[return_to_secure] & R_V7M_CONTROL_NPRIV_MAS= K); + + mmu_idx =3D arm_v7m_mmu_idx_for_secstate_and_priv(env, return_to_s= ecure, + return_to_priv); + + if (!QEMU_IS_ALIGNED(frameptr, 8) && + arm_feature(env, ARM_FEATURE_V8)) { + qemu_log_mask(LOG_GUEST_ERROR, + "M profile exception return with non-8-aligned S= P " + "for destination state is UNPREDICTABLE\n"); + } + + /* Do we need to pop callee-saved registers? */ + if (return_to_secure && + ((excret & R_V7M_EXCRET_ES_MASK) =3D=3D 0 || + (excret & R_V7M_EXCRET_DCRS_MASK) =3D=3D 0)) { + uint32_t actual_sig; + + pop_ok =3D v7m_stack_read(cpu, &actual_sig, frameptr, mmu_idx); + + if (pop_ok && v7m_integrity_sig(env, excret) !=3D actual_sig) { + /* Take a SecureFault on the current stack */ + env->v7m.sfsr |=3D R_V7M_SFSR_INVIS_MASK; + armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_SECURE, fal= se); + qemu_log_mask(CPU_LOG_INT, "...taking SecureFault on exist= ing " + "stackframe: failed exception return integri= ty " + "signature check\n"); + v7m_exception_taken(cpu, excret, true, false); + return; + } + + pop_ok =3D pop_ok && + v7m_stack_read(cpu, &env->regs[4], frameptr + 0x8, mmu_idx= ) && + v7m_stack_read(cpu, &env->regs[5], frameptr + 0xc, mmu_idx= ) && + v7m_stack_read(cpu, &env->regs[6], frameptr + 0x10, mmu_id= x) && + v7m_stack_read(cpu, &env->regs[7], frameptr + 0x14, mmu_id= x) && + v7m_stack_read(cpu, &env->regs[8], frameptr + 0x18, mmu_id= x) && + v7m_stack_read(cpu, &env->regs[9], frameptr + 0x1c, mmu_id= x) && + v7m_stack_read(cpu, &env->regs[10], frameptr + 0x20, mmu_i= dx) && + v7m_stack_read(cpu, &env->regs[11], frameptr + 0x24, mmu_i= dx); + + frameptr +=3D 0x28; + } + + /* Pop registers */ + pop_ok =3D pop_ok && + v7m_stack_read(cpu, &env->regs[0], frameptr, mmu_idx) && + v7m_stack_read(cpu, &env->regs[1], frameptr + 0x4, mmu_idx) && + v7m_stack_read(cpu, &env->regs[2], frameptr + 0x8, mmu_idx) && + v7m_stack_read(cpu, &env->regs[3], frameptr + 0xc, mmu_idx) && + v7m_stack_read(cpu, &env->regs[12], frameptr + 0x10, mmu_idx) = && + v7m_stack_read(cpu, &env->regs[14], frameptr + 0x14, mmu_idx) = && + v7m_stack_read(cpu, &env->regs[15], frameptr + 0x18, mmu_idx) = && + v7m_stack_read(cpu, &xpsr, frameptr + 0x1c, mmu_idx); + + if (!pop_ok) { + /* + * v7m_stack_read() pended a fault, so take it (as a tail + * chained exception on the same stack frame) + */ + qemu_log_mask(CPU_LOG_INT, "...derived exception on unstacking= \n"); + v7m_exception_taken(cpu, excret, true, false); + return; + } + + /* + * Returning from an exception with a PC with bit 0 set is defined + * behaviour on v8M (bit 0 is ignored), but for v7M it was specifi= ed + * to be UNPREDICTABLE. In practice actual v7M hardware seems to i= gnore + * the lsbit, and there are several RTOSes out there which incorre= ctly + * assume the r15 in the stack frame should be a Thumb-style "lsbit + * indicates ARM/Thumb" value, so ignore the bit on v7M as well, b= ut + * complain about the badly behaved guest. + */ + if (env->regs[15] & 1) { + env->regs[15] &=3D ~1U; + if (!arm_feature(env, ARM_FEATURE_V8)) { + qemu_log_mask(LOG_GUEST_ERROR, + "M profile return from interrupt with misali= gned " + "PC is UNPREDICTABLE on v7M\n"); + } + } + + if (arm_feature(env, ARM_FEATURE_V8)) { + /* + * For v8M we have to check whether the xPSR exception field + * matches the EXCRET value for return to handler/thread + * before we commit to changing the SP and xPSR. + */ + bool will_be_handler =3D (xpsr & XPSR_EXCP) !=3D 0; + if (return_to_handler !=3D will_be_handler) { + /* + * Take an INVPC UsageFault on the current stack. + * By this point we will have switched to the security sta= te + * for the background state, so this UsageFault will target + * that state. + */ + armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_USAGE, + env->v7m.secure); + env->v7m.cfsr[env->v7m.secure] |=3D R_V7M_CFSR_INVPC_MASK; + qemu_log_mask(CPU_LOG_INT, "...taking UsageFault on existi= ng " + "stackframe: failed exception return integri= ty " + "check\n"); + v7m_exception_taken(cpu, excret, true, false); + return; + } + } + + if (!ftype) { + /* FP present and we need to handle it */ + if (!return_to_secure && + (env->v7m.fpccr[M_REG_S] & R_V7M_FPCCR_LSPACT_MASK)) { + armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_SECURE, fal= se); + env->v7m.sfsr |=3D R_V7M_SFSR_LSERR_MASK; + qemu_log_mask(CPU_LOG_INT, + "...taking SecureFault on existing stackfram= e: " + "Secure LSPACT set but exception return is " + "not to secure state\n"); + v7m_exception_taken(cpu, excret, true, false); + return; + } + + restore_s16_s31 =3D return_to_secure && + (env->v7m.fpccr[M_REG_S] & R_V7M_FPCCR_TS_MASK); + + if (env->v7m.fpccr[return_to_secure] & R_V7M_FPCCR_LSPACT_MASK= ) { + /* State in FPU is still valid, just clear LSPACT */ + env->v7m.fpccr[return_to_secure] &=3D ~R_V7M_FPCCR_LSPACT_= MASK; + } else { + int i; + uint32_t fpscr; + bool cpacr_pass, nsacr_pass; + + cpacr_pass =3D v7m_cpacr_pass(env, return_to_secure, + return_to_priv); + nsacr_pass =3D return_to_secure || + extract32(env->v7m.nsacr, 10, 1); + + if (!cpacr_pass) { + armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_USAGE, + return_to_secure); + env->v7m.cfsr[return_to_secure] |=3D R_V7M_CFSR_NOCP_M= ASK; + qemu_log_mask(CPU_LOG_INT, + "...taking UsageFault on existing " + "stackframe: CPACR.CP10 prevents unstack= ing " + "FP regs\n"); + v7m_exception_taken(cpu, excret, true, false); + return; + } else if (!nsacr_pass) { + armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_USAGE, = true); + env->v7m.cfsr[M_REG_S] |=3D R_V7M_CFSR_INVPC_MASK; + qemu_log_mask(CPU_LOG_INT, + "...taking Secure UsageFault on existing= " + "stackframe: NSACR.CP10 prevents unstack= ing " + "FP regs\n"); + v7m_exception_taken(cpu, excret, true, false); + return; + } + + for (i =3D 0; i < (restore_s16_s31 ? 32 : 16); i +=3D 2) { + uint32_t slo, shi; + uint64_t dn; + uint32_t faddr =3D frameptr + 0x20 + 4 * i; + + if (i >=3D 16) { + faddr +=3D 8; /* Skip the slot for the FPSCR */ + } + + pop_ok =3D pop_ok && + v7m_stack_read(cpu, &slo, faddr, mmu_idx) && + v7m_stack_read(cpu, &shi, faddr + 4, mmu_idx); + + if (!pop_ok) { + break; + } + + dn =3D (uint64_t)shi << 32 | slo; + *aa32_vfp_dreg(env, i / 2) =3D dn; + } + pop_ok =3D pop_ok && + v7m_stack_read(cpu, &fpscr, frameptr + 0x60, mmu_idx); + if (pop_ok) { + vfp_set_fpscr(env, fpscr); + } + if (!pop_ok) { + /* + * These regs are 0 if security extension present; + * otherwise merely UNKNOWN. We zero always. + */ + for (i =3D 0; i < (restore_s16_s31 ? 32 : 16); i +=3D = 2) { + *aa32_vfp_dreg(env, i / 2) =3D 0; + } + vfp_set_fpscr(env, 0); + } + } + } + env->v7m.control[M_REG_S] =3D FIELD_DP32(env->v7m.control[M_REG_S], + V7M_CONTROL, FPCA, !ftype); + + /* Commit to consuming the stack frame */ + frameptr +=3D 0x20; + if (!ftype) { + frameptr +=3D 0x48; + if (restore_s16_s31) { + frameptr +=3D 0x40; + } + } + /* + * Undo stack alignment (the SPREALIGN bit indicates that the orig= inal + * pre-exception SP was not 8-aligned and we added a padding word = to + * align it, so we undo this by ORing in the bit that increases it + * from the current 8-aligned value to the 8-unaligned value. (Add= ing 4 + * would work too but a logical OR is how the pseudocode specifies= it.) + */ + if (xpsr & XPSR_SPREALIGN) { + frameptr |=3D 4; + } + *frame_sp_p =3D frameptr; + } + + xpsr_mask =3D ~(XPSR_SPREALIGN | XPSR_SFPA); + if (!arm_feature(env, ARM_FEATURE_THUMB_DSP)) { + xpsr_mask &=3D ~XPSR_GE; + } + /* This xpsr_write() will invalidate frame_sp_p as it may switch stack= */ + xpsr_write(env, xpsr, xpsr_mask); + + if (env->v7m.secure) { + bool sfpa =3D xpsr & XPSR_SFPA; + + env->v7m.control[M_REG_S] =3D FIELD_DP32(env->v7m.control[M_REG_S], + V7M_CONTROL, SFPA, sfpa); + } + + /* + * The restored xPSR exception field will be zero if we're + * resuming in Thread mode. If that doesn't match what the + * exception return excret specified then this is a UsageFault. + * v7M requires we make this check here; v8M did it earlier. + */ + if (return_to_handler !=3D arm_v7m_is_handler_mode(env)) { + /* + * Take an INVPC UsageFault by pushing the stack again; + * we know we're v7M so this is never a Secure UsageFault. + */ + bool ignore_stackfaults; + + assert(!arm_feature(env, ARM_FEATURE_V8)); + armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_USAGE, false); + env->v7m.cfsr[env->v7m.secure] |=3D R_V7M_CFSR_INVPC_MASK; + ignore_stackfaults =3D v7m_push_stack(cpu); + qemu_log_mask(CPU_LOG_INT, "...taking UsageFault on new stackframe= : " + "failed exception return integrity check\n"); + v7m_exception_taken(cpu, excret, false, ignore_stackfaults); + return; + } + + /* Otherwise, we have a successful exception exit. */ + arm_clear_exclusive(env); + qemu_log_mask(CPU_LOG_INT, "...successful exception return\n"); +} + +static bool do_v7m_function_return(ARMCPU *cpu) +{ + /* + * v8M security extensions magic function return. + * We may either: + * (1) throw an exception (longjump) + * (2) return true if we successfully handled the function return + * (3) return false if we failed a consistency check and have + * pended a UsageFault that needs to be taken now + * + * At this point the magic return value is split between env->regs[15] + * and env->thumb. We don't bother to reconstitute it because we don't + * need it (all values are handled the same way). + */ + CPUARMState *env =3D &cpu->env; + uint32_t newpc, newpsr, newpsr_exc; + + qemu_log_mask(CPU_LOG_INT, "...really v7M secure function return\n"); + + { + bool threadmode, spsel; + TCGMemOpIdx oi; + ARMMMUIdx mmu_idx; + uint32_t *frame_sp_p; + uint32_t frameptr; + + /* Pull the return address and IPSR from the Secure stack */ + threadmode =3D !arm_v7m_is_handler_mode(env); + spsel =3D env->v7m.control[M_REG_S] & R_V7M_CONTROL_SPSEL_MASK; + + frame_sp_p =3D get_v7m_sp_ptr(env, true, threadmode, spsel); + frameptr =3D *frame_sp_p; + + /* + * These loads may throw an exception (for MPU faults). We want to + * do them as secure, so work out what MMU index that is. + */ + mmu_idx =3D arm_v7m_mmu_idx_for_secstate(env, true); + oi =3D make_memop_idx(MO_LE, arm_to_core_mmu_idx(mmu_idx)); + newpc =3D helper_le_ldul_mmu(env, frameptr, oi, 0); + newpsr =3D helper_le_ldul_mmu(env, frameptr + 4, oi, 0); + + /* Consistency checks on new IPSR */ + newpsr_exc =3D newpsr & XPSR_EXCP; + if (!((env->v7m.exception =3D=3D 0 && newpsr_exc =3D=3D 0) || + (env->v7m.exception =3D=3D 1 && newpsr_exc !=3D 0))) { + /* Pend the fault and tell our caller to take it */ + env->v7m.cfsr[env->v7m.secure] |=3D R_V7M_CFSR_INVPC_MASK; + armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_USAGE, + env->v7m.secure); + qemu_log_mask(CPU_LOG_INT, + "...taking INVPC UsageFault: " + "IPSR consistency check failed\n"); + return false; + } + + *frame_sp_p =3D frameptr + 8; + } + + /* This invalidates frame_sp_p */ + switch_v7m_security_state(env, true); + env->v7m.exception =3D newpsr_exc; + env->v7m.control[M_REG_S] &=3D ~R_V7M_CONTROL_SFPA_MASK; + if (newpsr & XPSR_SFPA) { + env->v7m.control[M_REG_S] |=3D R_V7M_CONTROL_SFPA_MASK; + } + xpsr_write(env, 0, XPSR_IT); + env->thumb =3D newpc & 1; + env->regs[15] =3D newpc & ~1; + + qemu_log_mask(CPU_LOG_INT, "...function return successful\n"); + return true; +} + +static bool v7m_read_half_insn(ARMCPU *cpu, ARMMMUIdx mmu_idx, + uint32_t addr, uint16_t *insn) +{ + /* + * Load a 16-bit portion of a v7M instruction, returning true on succe= ss, + * or false on failure (in which case we will have pended the appropri= ate + * exception). + * We need to do the instruction fetch's MPU and SAU checks + * like this because there is no MMU index that would allow + * doing the load with a single function call. Instead we must + * first check that the security attributes permit the load + * and that they don't mismatch on the two halves of the instruction, + * and then we do the load as a secure load (ie using the security + * attributes of the address, not the CPU, as architecturally required= ). + */ + CPUState *cs =3D CPU(cpu); + CPUARMState *env =3D &cpu->env; + V8M_SAttributes sattrs =3D {}; + MemTxAttrs attrs =3D {}; + ARMMMUFaultInfo fi =3D {}; + MemTxResult txres; + target_ulong page_size; + hwaddr physaddr; + int prot; + + v8m_security_lookup(env, addr, MMU_INST_FETCH, mmu_idx, &sattrs); + if (!sattrs.nsc || sattrs.ns) { + /* + * This must be the second half of the insn, and it straddles a + * region boundary with the second half not being S&NSC. + */ + env->v7m.sfsr |=3D R_V7M_SFSR_INVEP_MASK; + armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_SECURE, false); + qemu_log_mask(CPU_LOG_INT, + "...really SecureFault with SFSR.INVEP\n"); + return false; + } + if (get_phys_addr(env, addr, MMU_INST_FETCH, mmu_idx, + &physaddr, &attrs, &prot, &page_size, &fi, NULL)) { + /* the MPU lookup failed */ + env->v7m.cfsr[env->v7m.secure] |=3D R_V7M_CFSR_IACCVIOL_MASK; + armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_MEM, env->v7m.secur= e); + qemu_log_mask(CPU_LOG_INT, "...really MemManage with CFSR.IACCVIOL= \n"); + return false; + } + *insn =3D address_space_lduw_le(arm_addressspace(cs, attrs), physaddr, + attrs, &txres); + if (txres !=3D MEMTX_OK) { + env->v7m.cfsr[M_REG_NS] |=3D R_V7M_CFSR_IBUSERR_MASK; + armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_BUS, false); + qemu_log_mask(CPU_LOG_INT, "...really BusFault with CFSR.IBUSERR\n= "); + return false; + } + return true; +} + +static bool v7m_handle_execute_nsc(ARMCPU *cpu) +{ + /* + * Check whether this attempt to execute code in a Secure & NS-Callable + * memory region is for an SG instruction; if so, then emulate the + * effect of the SG instruction and return true. Otherwise pend + * the correct kind of exception and return false. + */ + CPUARMState *env =3D &cpu->env; + ARMMMUIdx mmu_idx; + uint16_t insn; + + /* + * We should never get here unless get_phys_addr_pmsav8() caused + * an exception for NS executing in S&NSC memory. + */ + assert(!env->v7m.secure); + assert(arm_feature(env, ARM_FEATURE_M_SECURITY)); + + /* We want to do the MPU lookup as secure; work out what mmu_idx that = is */ + mmu_idx =3D arm_v7m_mmu_idx_for_secstate(env, true); + + if (!v7m_read_half_insn(cpu, mmu_idx, env->regs[15], &insn)) { + return false; + } + + if (!env->thumb) { + goto gen_invep; + } + + if (insn !=3D 0xe97f) { + /* + * Not an SG instruction first half (we choose the IMPDEF + * early-SG-check option). + */ + goto gen_invep; + } + + if (!v7m_read_half_insn(cpu, mmu_idx, env->regs[15] + 2, &insn)) { + return false; + } + + if (insn !=3D 0xe97f) { + /* + * Not an SG instruction second half (yes, both halves of the SG + * insn have the same hex value) + */ + goto gen_invep; + } + + /* + * OK, we have confirmed that we really have an SG instruction. + * We know we're NS in S memory so don't need to repeat those checks. + */ + qemu_log_mask(CPU_LOG_INT, "...really an SG instruction at 0x%08" PRIx= 32 + ", executing it\n", env->regs[15]); + env->regs[14] &=3D ~1; + env->v7m.control[M_REG_S] &=3D ~R_V7M_CONTROL_SFPA_MASK; + switch_v7m_security_state(env, true); + xpsr_write(env, 0, XPSR_IT); + env->regs[15] +=3D 4; + return true; + +gen_invep: + env->v7m.sfsr |=3D R_V7M_SFSR_INVEP_MASK; + armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_SECURE, false); + qemu_log_mask(CPU_LOG_INT, + "...really SecureFault with SFSR.INVEP\n"); + return false; +} + +void arm_v7m_cpu_do_interrupt(CPUState *cs) +{ + ARMCPU *cpu =3D ARM_CPU(cs); + CPUARMState *env =3D &cpu->env; + uint32_t lr; + bool ignore_stackfaults; + + arm_log_exception(cs->exception_index); + + /* + * For exceptions we just mark as pending on the NVIC, and let that + * handle it. + */ + switch (cs->exception_index) { + case EXCP_UDEF: + armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_USAGE, env->v7m.sec= ure); + env->v7m.cfsr[env->v7m.secure] |=3D R_V7M_CFSR_UNDEFINSTR_MASK; + break; + case EXCP_NOCP: + { + /* + * NOCP might be directed to something other than the current + * security state if this fault is because of NSACR; we indicate + * the target security state using exception.target_el. + */ + int target_secstate; + + if (env->exception.target_el =3D=3D 3) { + target_secstate =3D M_REG_S; + } else { + target_secstate =3D env->v7m.secure; + } + armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_USAGE, target_secst= ate); + env->v7m.cfsr[target_secstate] |=3D R_V7M_CFSR_NOCP_MASK; + break; + } + case EXCP_INVSTATE: + armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_USAGE, env->v7m.sec= ure); + env->v7m.cfsr[env->v7m.secure] |=3D R_V7M_CFSR_INVSTATE_MASK; + break; + case EXCP_STKOF: + armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_USAGE, env->v7m.sec= ure); + env->v7m.cfsr[env->v7m.secure] |=3D R_V7M_CFSR_STKOF_MASK; + break; + case EXCP_LSERR: + armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_SECURE, false); + env->v7m.sfsr |=3D R_V7M_SFSR_LSERR_MASK; + break; + case EXCP_UNALIGNED: + armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_USAGE, env->v7m.sec= ure); + env->v7m.cfsr[env->v7m.secure] |=3D R_V7M_CFSR_UNALIGNED_MASK; + break; + case EXCP_SWI: + /* The PC already points to the next instruction. */ + armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_SVC, env->v7m.secur= e); + break; + case EXCP_PREFETCH_ABORT: + case EXCP_DATA_ABORT: + /* + * Note that for M profile we don't have a guest facing FSR, but + * the env->exception.fsr will be populated by the code that + * raises the fault, in the A profile short-descriptor format. + */ + switch (env->exception.fsr & 0xf) { + case M_FAKE_FSR_NSC_EXEC: + /* + * Exception generated when we try to execute code at an addre= ss + * which is marked as Secure & Non-Secure Callable and the CPU + * is in the Non-Secure state. The only instruction which can + * be executed like this is SG (and that only if both halves of + * the SG instruction have the same security attributes.) + * Everything else must generate an INVEP SecureFault, so we + * emulate the SG instruction here. + */ + if (v7m_handle_execute_nsc(cpu)) { + return; + } + break; + case M_FAKE_FSR_SFAULT: + /* + * Various flavours of SecureFault for attempts to execute or + * access data in the wrong security state. + */ + switch (cs->exception_index) { + case EXCP_PREFETCH_ABORT: + if (env->v7m.secure) { + env->v7m.sfsr |=3D R_V7M_SFSR_INVTRAN_MASK; + qemu_log_mask(CPU_LOG_INT, + "...really SecureFault with SFSR.INVTRAN= \n"); + } else { + env->v7m.sfsr |=3D R_V7M_SFSR_INVEP_MASK; + qemu_log_mask(CPU_LOG_INT, + "...really SecureFault with SFSR.INVEP\n= "); + } + break; + case EXCP_DATA_ABORT: + /* This must be an NS access to S memory */ + env->v7m.sfsr |=3D R_V7M_SFSR_AUVIOL_MASK; + qemu_log_mask(CPU_LOG_INT, + "...really SecureFault with SFSR.AUVIOL\n"); + break; + } + armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_SECURE, false); + break; + case 0x8: /* External Abort */ + switch (cs->exception_index) { + case EXCP_PREFETCH_ABORT: + env->v7m.cfsr[M_REG_NS] |=3D R_V7M_CFSR_IBUSERR_MASK; + qemu_log_mask(CPU_LOG_INT, "...with CFSR.IBUSERR\n"); + break; + case EXCP_DATA_ABORT: + env->v7m.cfsr[M_REG_NS] |=3D + (R_V7M_CFSR_PRECISERR_MASK | R_V7M_CFSR_BFARVALID_MASK= ); + env->v7m.bfar =3D env->exception.vaddress; + qemu_log_mask(CPU_LOG_INT, + "...with CFSR.PRECISERR and BFAR 0x%x\n", + env->v7m.bfar); + break; + } + armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_BUS, false); + break; + default: + /* + * All other FSR values are either MPU faults or "can't happen + * for M profile" cases. + */ + switch (cs->exception_index) { + case EXCP_PREFETCH_ABORT: + env->v7m.cfsr[env->v7m.secure] |=3D R_V7M_CFSR_IACCVIOL_MA= SK; + qemu_log_mask(CPU_LOG_INT, "...with CFSR.IACCVIOL\n"); + break; + case EXCP_DATA_ABORT: + env->v7m.cfsr[env->v7m.secure] |=3D + (R_V7M_CFSR_DACCVIOL_MASK | R_V7M_CFSR_MMARVALID_MASK); + env->v7m.mmfar[env->v7m.secure] =3D env->exception.vaddres= s; + qemu_log_mask(CPU_LOG_INT, + "...with CFSR.DACCVIOL and MMFAR 0x%x\n", + env->v7m.mmfar[env->v7m.secure]); + break; + } + armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_MEM, + env->v7m.secure); + break; + } + break; + case EXCP_BKPT: + if (semihosting_enabled()) { + int nr; + nr =3D arm_lduw_code(env, env->regs[15], arm_sctlr_b(env)) & 0= xff; + if (nr =3D=3D 0xab) { + env->regs[15] +=3D 2; + qemu_log_mask(CPU_LOG_INT, + "...handling as semihosting call 0x%x\n", + env->regs[0]); + env->regs[0] =3D do_arm_semihosting(env); + return; + } + } + armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_DEBUG, false); + break; + case EXCP_IRQ: + break; + case EXCP_EXCEPTION_EXIT: + if (env->regs[15] < EXC_RETURN_MIN_MAGIC) { + /* Must be v8M security extension function return */ + assert(env->regs[15] >=3D FNC_RETURN_MIN_MAGIC); + assert(arm_feature(env, ARM_FEATURE_M_SECURITY)); + if (do_v7m_function_return(cpu)) { + return; + } + } else { + do_v7m_exception_exit(cpu); + return; + } + break; + case EXCP_LAZYFP: + /* + * We already pended the specific exception in the NVIC in the + * v7m_preserve_fp_state() helper function. + */ + break; + default: + cpu_abort(cs, "Unhandled exception 0x%x\n", cs->exception_index); + return; /* Never happens. Keep compiler happy. */ + } + + if (arm_feature(env, ARM_FEATURE_V8)) { + lr =3D R_V7M_EXCRET_RES1_MASK | + R_V7M_EXCRET_DCRS_MASK; + /* + * The S bit indicates whether we should return to Secure + * or NonSecure (ie our current state). + * The ES bit indicates whether we're taking this exception + * to Secure or NonSecure (ie our target state). We set it + * later, in v7m_exception_taken(). + * The SPSEL bit is also set in v7m_exception_taken() for v8M. + * This corresponds to the ARM ARM pseudocode for v8M setting + * some LR bits in PushStack() and some in ExceptionTaken(); + * the distinction matters for the tailchain cases where we + * can take an exception without pushing the stack. + */ + if (env->v7m.secure) { + lr |=3D R_V7M_EXCRET_S_MASK; + } + if (!(env->v7m.control[M_REG_S] & R_V7M_CONTROL_FPCA_MASK)) { + lr |=3D R_V7M_EXCRET_FTYPE_MASK; + } + } else { + lr =3D R_V7M_EXCRET_RES1_MASK | + R_V7M_EXCRET_S_MASK | + R_V7M_EXCRET_DCRS_MASK | + R_V7M_EXCRET_FTYPE_MASK | + R_V7M_EXCRET_ES_MASK; + if (env->v7m.control[M_REG_NS] & R_V7M_CONTROL_SPSEL_MASK) { + lr |=3D R_V7M_EXCRET_SPSEL_MASK; + } + } + if (!arm_v7m_is_handler_mode(env)) { + lr |=3D R_V7M_EXCRET_MODE_MASK; + } + + ignore_stackfaults =3D v7m_push_stack(cpu); + v7m_exception_taken(cpu, lr, false, ignore_stackfaults); +} + +uint32_t HELPER(v7m_mrs)(CPUARMState *env, uint32_t reg) +{ + uint32_t mask; + unsigned el =3D arm_current_el(env); + + /* First handle registers which unprivileged can read */ + + switch (reg) { + case 0 ... 7: /* xPSR sub-fields */ + mask =3D 0; + if ((reg & 1) && el) { + mask |=3D XPSR_EXCP; /* IPSR (unpriv. reads as zero) */ + } + if (!(reg & 4)) { + mask |=3D XPSR_NZCV | XPSR_Q; /* APSR */ + if (arm_feature(env, ARM_FEATURE_THUMB_DSP)) { + mask |=3D XPSR_GE; + } + } + /* EPSR reads as zero */ + return xpsr_read(env) & mask; + break; + case 20: /* CONTROL */ + { + uint32_t value =3D env->v7m.control[env->v7m.secure]; + if (!env->v7m.secure) { + /* SFPA is RAZ/WI from NS; FPCA is stored in the M_REG_S bank = */ + value |=3D env->v7m.control[M_REG_S] & R_V7M_CONTROL_FPCA_MASK; + } + return value; + } + case 0x94: /* CONTROL_NS */ + /* + * We have to handle this here because unprivileged Secure code + * can read the NS CONTROL register. + */ + if (!env->v7m.secure) { + return 0; + } + return env->v7m.control[M_REG_NS] | + (env->v7m.control[M_REG_S] & R_V7M_CONTROL_FPCA_MASK); + } + + if (el =3D=3D 0) { + return 0; /* unprivileged reads others as zero */ + } + + if (arm_feature(env, ARM_FEATURE_M_SECURITY)) { + switch (reg) { + case 0x88: /* MSP_NS */ + if (!env->v7m.secure) { + return 0; + } + return env->v7m.other_ss_msp; + case 0x89: /* PSP_NS */ + if (!env->v7m.secure) { + return 0; + } + return env->v7m.other_ss_psp; + case 0x8a: /* MSPLIM_NS */ + if (!env->v7m.secure) { + return 0; + } + return env->v7m.msplim[M_REG_NS]; + case 0x8b: /* PSPLIM_NS */ + if (!env->v7m.secure) { + return 0; + } + return env->v7m.psplim[M_REG_NS]; + case 0x90: /* PRIMASK_NS */ + if (!env->v7m.secure) { + return 0; + } + return env->v7m.primask[M_REG_NS]; + case 0x91: /* BASEPRI_NS */ + if (!env->v7m.secure) { + return 0; + } + return env->v7m.basepri[M_REG_NS]; + case 0x93: /* FAULTMASK_NS */ + if (!env->v7m.secure) { + return 0; + } + return env->v7m.faultmask[M_REG_NS]; + case 0x98: /* SP_NS */ + { + /* + * This gives the non-secure SP selected based on whether we're + * currently in handler mode or not, using the NS CONTROL.SPSE= L. + */ + bool spsel =3D env->v7m.control[M_REG_NS] & R_V7M_CONTROL_SPSE= L_MASK; + + if (!env->v7m.secure) { + return 0; + } + if (!arm_v7m_is_handler_mode(env) && spsel) { + return env->v7m.other_ss_psp; + } else { + return env->v7m.other_ss_msp; + } + } + default: + break; + } + } + + switch (reg) { + case 8: /* MSP */ + return v7m_using_psp(env) ? env->v7m.other_sp : env->regs[13]; + case 9: /* PSP */ + return v7m_using_psp(env) ? env->regs[13] : env->v7m.other_sp; + case 10: /* MSPLIM */ + if (!arm_feature(env, ARM_FEATURE_V8)) { + goto bad_reg; + } + return env->v7m.msplim[env->v7m.secure]; + case 11: /* PSPLIM */ + if (!arm_feature(env, ARM_FEATURE_V8)) { + goto bad_reg; + } + return env->v7m.psplim[env->v7m.secure]; + case 16: /* PRIMASK */ + return env->v7m.primask[env->v7m.secure]; + case 17: /* BASEPRI */ + case 18: /* BASEPRI_MAX */ + return env->v7m.basepri[env->v7m.secure]; + case 19: /* FAULTMASK */ + return env->v7m.faultmask[env->v7m.secure]; + default: + bad_reg: + qemu_log_mask(LOG_GUEST_ERROR, "Attempt to read unknown special" + " register %d\n", reg); + return 0; + } +} + +void HELPER(v7m_msr)(CPUARMState *env, uint32_t maskreg, uint32_t val) +{ + /* + * We're passed bits [11..0] of the instruction; extract + * SYSm and the mask bits. + * Invalid combinations of SYSm and mask are UNPREDICTABLE; + * we choose to treat them as if the mask bits were valid. + * NB that the pseudocode 'mask' variable is bits [11..10], + * whereas ours is [11..8]. + */ + uint32_t mask =3D extract32(maskreg, 8, 4); + uint32_t reg =3D extract32(maskreg, 0, 8); + int cur_el =3D arm_current_el(env); + + if (cur_el =3D=3D 0 && reg > 7 && reg !=3D 20) { + /* + * only xPSR sub-fields and CONTROL.SFPA may be written by + * unprivileged code + */ + return; + } + + if (arm_feature(env, ARM_FEATURE_M_SECURITY)) { + switch (reg) { + case 0x88: /* MSP_NS */ + if (!env->v7m.secure) { + return; + } + env->v7m.other_ss_msp =3D val; + return; + case 0x89: /* PSP_NS */ + if (!env->v7m.secure) { + return; + } + env->v7m.other_ss_psp =3D val; + return; + case 0x8a: /* MSPLIM_NS */ + if (!env->v7m.secure) { + return; + } + env->v7m.msplim[M_REG_NS] =3D val & ~7; + return; + case 0x8b: /* PSPLIM_NS */ + if (!env->v7m.secure) { + return; + } + env->v7m.psplim[M_REG_NS] =3D val & ~7; + return; + case 0x90: /* PRIMASK_NS */ + if (!env->v7m.secure) { + return; + } + env->v7m.primask[M_REG_NS] =3D val & 1; + return; + case 0x91: /* BASEPRI_NS */ + if (!env->v7m.secure || !arm_feature(env, ARM_FEATURE_M_MAIN))= { + return; + } + env->v7m.basepri[M_REG_NS] =3D val & 0xff; + return; + case 0x93: /* FAULTMASK_NS */ + if (!env->v7m.secure || !arm_feature(env, ARM_FEATURE_M_MAIN))= { + return; + } + env->v7m.faultmask[M_REG_NS] =3D val & 1; + return; + case 0x94: /* CONTROL_NS */ + if (!env->v7m.secure) { + return; + } + write_v7m_control_spsel_for_secstate(env, + val & R_V7M_CONTROL_SPSEL= _MASK, + M_REG_NS); + if (arm_feature(env, ARM_FEATURE_M_MAIN)) { + env->v7m.control[M_REG_NS] &=3D ~R_V7M_CONTROL_NPRIV_MASK; + env->v7m.control[M_REG_NS] |=3D val & R_V7M_CONTROL_NPRIV_= MASK; + } + /* + * SFPA is RAZ/WI from NS. FPCA is RO if NSACR.CP10 =3D=3D 0, + * RES0 if the FPU is not present, and is stored in the S bank + */ + if (arm_feature(env, ARM_FEATURE_VFP) && + extract32(env->v7m.nsacr, 10, 1)) { + env->v7m.control[M_REG_S] &=3D ~R_V7M_CONTROL_FPCA_MASK; + env->v7m.control[M_REG_S] |=3D val & R_V7M_CONTROL_FPCA_MA= SK; + } + return; + case 0x98: /* SP_NS */ + { + /* + * This gives the non-secure SP selected based on whether we're + * currently in handler mode or not, using the NS CONTROL.SPSE= L. + */ + bool spsel =3D env->v7m.control[M_REG_NS] & R_V7M_CONTROL_SPSE= L_MASK; + bool is_psp =3D !arm_v7m_is_handler_mode(env) && spsel; + uint32_t limit; + + if (!env->v7m.secure) { + return; + } + + limit =3D is_psp ? env->v7m.psplim[false] : env->v7m.msplim[fa= lse]; + + if (val < limit) { + CPUState *cs =3D env_cpu(env); + + cpu_restore_state(cs, GETPC(), true); + raise_exception(env, EXCP_STKOF, 0, 1); + } + + if (is_psp) { + env->v7m.other_ss_psp =3D val; + } else { + env->v7m.other_ss_msp =3D val; + } + return; + } + default: + break; + } + } + + switch (reg) { + case 0 ... 7: /* xPSR sub-fields */ + /* only APSR is actually writable */ + if (!(reg & 4)) { + uint32_t apsrmask =3D 0; + + if (mask & 8) { + apsrmask |=3D XPSR_NZCV | XPSR_Q; + } + if ((mask & 4) && arm_feature(env, ARM_FEATURE_THUMB_DSP)) { + apsrmask |=3D XPSR_GE; + } + xpsr_write(env, val, apsrmask); + } + break; + case 8: /* MSP */ + if (v7m_using_psp(env)) { + env->v7m.other_sp =3D val; + } else { + env->regs[13] =3D val; + } + break; + case 9: /* PSP */ + if (v7m_using_psp(env)) { + env->regs[13] =3D val; + } else { + env->v7m.other_sp =3D val; + } + break; + case 10: /* MSPLIM */ + if (!arm_feature(env, ARM_FEATURE_V8)) { + goto bad_reg; + } + env->v7m.msplim[env->v7m.secure] =3D val & ~7; + break; + case 11: /* PSPLIM */ + if (!arm_feature(env, ARM_FEATURE_V8)) { + goto bad_reg; + } + env->v7m.psplim[env->v7m.secure] =3D val & ~7; + break; + case 16: /* PRIMASK */ + env->v7m.primask[env->v7m.secure] =3D val & 1; + break; + case 17: /* BASEPRI */ + if (!arm_feature(env, ARM_FEATURE_M_MAIN)) { + goto bad_reg; + } + env->v7m.basepri[env->v7m.secure] =3D val & 0xff; + break; + case 18: /* BASEPRI_MAX */ + if (!arm_feature(env, ARM_FEATURE_M_MAIN)) { + goto bad_reg; + } + val &=3D 0xff; + if (val !=3D 0 && (val < env->v7m.basepri[env->v7m.secure] + || env->v7m.basepri[env->v7m.secure] =3D=3D 0)) { + env->v7m.basepri[env->v7m.secure] =3D val; + } + break; + case 19: /* FAULTMASK */ + if (!arm_feature(env, ARM_FEATURE_M_MAIN)) { + goto bad_reg; + } + env->v7m.faultmask[env->v7m.secure] =3D val & 1; + break; + case 20: /* CONTROL */ + /* + * Writing to the SPSEL bit only has an effect if we are in + * thread mode; other bits can be updated by any privileged code. + * write_v7m_control_spsel() deals with updating the SPSEL bit in + * env->v7m.control, so we only need update the others. + * For v7M, we must just ignore explicit writes to SPSEL in handler + * mode; for v8M the write is permitted but will have no effect. + * All these bits are writes-ignored from non-privileged code, + * except for SFPA. + */ + if (cur_el > 0 && (arm_feature(env, ARM_FEATURE_V8) || + !arm_v7m_is_handler_mode(env))) { + write_v7m_control_spsel(env, (val & R_V7M_CONTROL_SPSEL_MASK) = !=3D 0); + } + if (cur_el > 0 && arm_feature(env, ARM_FEATURE_M_MAIN)) { + env->v7m.control[env->v7m.secure] &=3D ~R_V7M_CONTROL_NPRIV_MA= SK; + env->v7m.control[env->v7m.secure] |=3D val & R_V7M_CONTROL_NPR= IV_MASK; + } + if (arm_feature(env, ARM_FEATURE_VFP)) { + /* + * SFPA is RAZ/WI from NS or if no FPU. + * FPCA is RO if NSACR.CP10 =3D=3D 0, RES0 if the FPU is not p= resent. + * Both are stored in the S bank. + */ + if (env->v7m.secure) { + env->v7m.control[M_REG_S] &=3D ~R_V7M_CONTROL_SFPA_MASK; + env->v7m.control[M_REG_S] |=3D val & R_V7M_CONTROL_SFPA_MA= SK; + } + if (cur_el > 0 && + (env->v7m.secure || !arm_feature(env, ARM_FEATURE_M_SECURI= TY) || + extract32(env->v7m.nsacr, 10, 1))) { + env->v7m.control[M_REG_S] &=3D ~R_V7M_CONTROL_FPCA_MASK; + env->v7m.control[M_REG_S] |=3D val & R_V7M_CONTROL_FPCA_MA= SK; + } + } + break; + default: + bad_reg: + qemu_log_mask(LOG_GUEST_ERROR, "Attempt to write unknown special" + " register %d\n", reg); + return; + } +} + +uint32_t HELPER(v7m_tt)(CPUARMState *env, uint32_t addr, uint32_t op) +{ + /* Implement the TT instruction. op is bits [7:6] of the insn. */ + bool forceunpriv =3D op & 1; + bool alt =3D op & 2; + V8M_SAttributes sattrs =3D {}; + uint32_t tt_resp; + bool r, rw, nsr, nsrw, mrvalid; + int prot; + ARMMMUFaultInfo fi =3D {}; + MemTxAttrs attrs =3D {}; + hwaddr phys_addr; + ARMMMUIdx mmu_idx; + uint32_t mregion; + bool targetpriv; + bool targetsec =3D env->v7m.secure; + bool is_subpage; + + /* + * Work out what the security state and privilege level we're + * interested in is... + */ + if (alt) { + targetsec =3D !targetsec; + } + + if (forceunpriv) { + targetpriv =3D false; + } else { + targetpriv =3D arm_v7m_is_handler_mode(env) || + !(env->v7m.control[targetsec] & R_V7M_CONTROL_NPRIV_MASK); + } + + /* ...and then figure out which MMU index this is */ + mmu_idx =3D arm_v7m_mmu_idx_for_secstate_and_priv(env, targetsec, targ= etpriv); + + /* + * We know that the MPU and SAU don't care about the access type + * for our purposes beyond that we don't want to claim to be + * an insn fetch, so we arbitrarily call this a read. + */ + + /* + * MPU region info only available for privileged or if + * inspecting the other MPU state. + */ + if (arm_current_el(env) !=3D 0 || alt) { + /* We can ignore the return value as prot is always set */ + pmsav8_mpu_lookup(env, addr, MMU_DATA_LOAD, mmu_idx, + &phys_addr, &attrs, &prot, &is_subpage, + &fi, &mregion); + if (mregion =3D=3D -1) { + mrvalid =3D false; + mregion =3D 0; + } else { + mrvalid =3D true; + } + r =3D prot & PAGE_READ; + rw =3D prot & PAGE_WRITE; + } else { + r =3D false; + rw =3D false; + mrvalid =3D false; + mregion =3D 0; + } + + if (env->v7m.secure) { + v8m_security_lookup(env, addr, MMU_DATA_LOAD, mmu_idx, &sattrs); + nsr =3D sattrs.ns && r; + nsrw =3D sattrs.ns && rw; + } else { + sattrs.ns =3D true; + nsr =3D false; + nsrw =3D false; + } + + tt_resp =3D (sattrs.iregion << 24) | + (sattrs.irvalid << 23) | + ((!sattrs.ns) << 22) | + (nsrw << 21) | + (nsr << 20) | + (rw << 19) | + (r << 18) | + (sattrs.srvalid << 17) | + (mrvalid << 16) | + (sattrs.sregion << 8) | + mregion; + + return tt_resp; +} + +#endif /* !CONFIG_USER_ONLY */ + +ARMMMUIdx arm_v7m_mmu_idx_all(CPUARMState *env, + bool secstate, bool priv, bool negpri) +{ + ARMMMUIdx mmu_idx =3D ARM_MMU_IDX_M; + + if (priv) { + mmu_idx |=3D ARM_MMU_IDX_M_PRIV; + } + + if (negpri) { + mmu_idx |=3D ARM_MMU_IDX_M_NEGPRI; + } + + if (secstate) { + mmu_idx |=3D ARM_MMU_IDX_M_S; + } + + return mmu_idx; +} + +ARMMMUIdx arm_v7m_mmu_idx_for_secstate_and_priv(CPUARMState *env, + bool secstate, bool priv) +{ + bool negpri =3D armv7m_nvic_neg_prio_requested(env->nvic, secstate); + + return arm_v7m_mmu_idx_all(env, secstate, priv, negpri); +} + +/* Return the MMU index for a v7M CPU in the specified security state */ +ARMMMUIdx arm_v7m_mmu_idx_for_secstate(CPUARMState *env, bool secstate) +{ + bool priv =3D arm_current_el(env) !=3D 0; + + return arm_v7m_mmu_idx_for_secstate_and_priv(env, secstate, priv); +} --=20 2.20.1 From nobody Mon May 13 12:20:01 2024 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=1562019423; cv=none; d=zoho.com; s=zohoarc; b=F+Y5klUnJbTr3Ayz7rd+9hTafQxM8mIVI97pimRot9RzM/a9R5PH08iunTqqfq5WUogpGUzp4Ktdd4emw0MhH1Rj/fDt9DaoF0PCrSM6fUk41XzJ1cfznMi3wVk00y5dJ+EmojZ2BMZ5u6xF7J5eAh5gK6DvZCtlSZWmy9RQaUw= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zoho.com; s=zohoarc; t=1562019423; h=Content-Type: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=Km5gA8ZOuNsU8q3/pBu/RSlZkTTXNXH79Hnd4urcGyA=; b=A8tplEnjzHYPwMA6Xjz17zcbXEYMBTfvXqmeHm9WVIl596QSxalPHKilBo+pu3GwD90Oc5psGqorcJ21blL3DSvobzO3n4JA+koAzh+xpONeUqfqHaIdJvJCtfATJbl4G7Q2Yh+G63nJJzd/DYmH/9MPij41bhkJYGaouMbb5pA= 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 156201942318584.2149550302014; Mon, 1 Jul 2019 15:17:03 -0700 (PDT) Received: from localhost ([::1]:46002 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.86_2) (envelope-from ) id 1hi4bc-0006Nr-4t for importer@patchew.org; Mon, 01 Jul 2019 18:17:00 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:54780) by lists.gnu.org with esmtp (Exim 4.86_2) (envelope-from ) id 1hi3WG-0006k1-Ph for qemu-devel@nongnu.org; Mon, 01 Jul 2019 17:07:25 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1hi3WF-0005bj-Mj for qemu-devel@nongnu.org; Mon, 01 Jul 2019 17:07:24 -0400 Received: from mx1.redhat.com ([209.132.183.28]:33570) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1hi3WC-0005Tx-7Y; Mon, 01 Jul 2019 17:07:20 -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 4BFAB3162916; Mon, 1 Jul 2019 19:50:14 +0000 (UTC) Received: from x1w.redhat.com (unknown [10.40.205.170]) by smtp.corp.redhat.com (Postfix) with ESMTPS id 344429089; Mon, 1 Jul 2019 19:50:06 +0000 (UTC) From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= To: qemu-devel@nongnu.org Date: Mon, 1 Jul 2019 21:49:38 +0200 Message-Id: <20190701194942.10092-5-philmd@redhat.com> In-Reply-To: <20190701194942.10092-1-philmd@redhat.com> References: <20190701194942.10092-1-philmd@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.41]); Mon, 01 Jul 2019 19:50:14 +0000 (UTC) Content-Transfer-Encoding: quoted-printable X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] X-Received-From: 209.132.183.28 Subject: [Qemu-devel] [PATCH v4 4/8] RFC target/arm: Restrict pre-ARMv7 cpus to TCG 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: Yang Zhong , Peter Maydell , Andrew Jones , Samuel Ortiz , Rob Bradford , =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= , Thomas Huth , qemu-arm@nongnu.org, Paolo Bonzini , =?UTF-8?q?Alex=20Benn=C3=A9e?= Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" Content-Type: text/plain; charset="utf-8" KVM requires at least a ARMv7 cpu. Signed-off-by: Philippe Mathieu-Daud=C3=A9 --- target/arm/cpu.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/target/arm/cpu.c b/target/arm/cpu.c index ca718fb38f..290ef16e52 100644 --- a/target/arm/cpu.c +++ b/target/arm/cpu.c @@ -1643,6 +1643,8 @@ static ObjectClass *arm_cpu_class_by_name(const char = *cpu_model) /* CPU models. These are not needed for the AArch64 linux-user build. */ #if !defined(CONFIG_USER_ONLY) || !defined(TARGET_AARCH64) =20 +#ifdef CONFIG_TCG + static void arm926_initfn(Object *obj) { ARMCPU *cpu =3D ARM_CPU(obj); @@ -1853,6 +1855,8 @@ static void cortex_m0_initfn(Object *obj) cpu->midr =3D 0x410cc200; } =20 +#endif + static void cortex_m3_initfn(Object *obj) { ARMCPU *cpu =3D ARM_CPU(obj); @@ -2234,6 +2238,8 @@ static void cortex_a15_initfn(Object *obj) define_arm_cp_regs(cpu, cortexa15_cp_reginfo); } =20 +#ifdef CONFIG_TCG + static void ti925t_initfn(Object *obj) { ARMCPU *cpu =3D ARM_CPU(obj); @@ -2402,6 +2408,8 @@ static void pxa270c5_initfn(Object *obj) cpu->reset_sctlr =3D 0x00000078; } =20 +#endif + #ifndef TARGET_AARCH64 /* -cpu max: if KVM is enabled, like -cpu host (best possible with this ho= st); * otherwise, a CPU with as many features enabled as our emulation support= s. @@ -2470,6 +2478,7 @@ struct ARMCPUInfo { =20 static const ARMCPUInfo arm_cpus[] =3D { #if !defined(CONFIG_USER_ONLY) || !defined(TARGET_AARCH64) +#ifdef CONFIG_TCG { .name =3D "arm926", .initfn =3D arm926_initfn }, { .name =3D "arm946", .initfn =3D arm946_initfn }, { .name =3D "arm1026", .initfn =3D arm1026_initfn }, @@ -2482,6 +2491,7 @@ static const ARMCPUInfo arm_cpus[] =3D { { .name =3D "arm1176", .initfn =3D arm1176_initfn }, { .name =3D "arm11mpcore", .initfn =3D arm11mpcore_initfn }, { .name =3D "cortex-m0", .initfn =3D cortex_m0_initfn, +#endif .class_init =3D arm_v7m_class_init }, { .name =3D "cortex-m3", .initfn =3D cortex_m3_initfn, .class_init =3D arm_v7m_class_init }, @@ -2495,6 +2505,7 @@ static const ARMCPUInfo arm_cpus[] =3D { { .name =3D "cortex-a8", .initfn =3D cortex_a8_initfn }, { .name =3D "cortex-a9", .initfn =3D cortex_a9_initfn }, { .name =3D "cortex-a15", .initfn =3D cortex_a15_initfn }, +#ifdef CONFIG_TCG { .name =3D "ti925t", .initfn =3D ti925t_initfn }, { .name =3D "sa1100", .initfn =3D sa1100_initfn }, { .name =3D "sa1110", .initfn =3D sa1110_initfn }, @@ -2511,6 +2522,7 @@ static const ARMCPUInfo arm_cpus[] =3D { { .name =3D "pxa270-b1", .initfn =3D pxa270b1_initfn }, { .name =3D "pxa270-c0", .initfn =3D pxa270c0_initfn }, { .name =3D "pxa270-c5", .initfn =3D pxa270c5_initfn }, +#endif #ifndef TARGET_AARCH64 { .name =3D "max", .initfn =3D arm_max_initfn }, #endif --=20 2.20.1 From nobody Mon May 13 12:20:01 2024 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=1562030877; cv=none; d=zoho.com; s=zohoarc; b=Fc9Z5mutDGUOYCYrB6k0RHb0tfhmOAUdePBrz6N+cF1QgY8V0NGAwXUpOsuj0Cgcws6Ky1ukg8ZbpRTQU57UcO/69BW53uogajXEMkOfV6IdogwDyJfW5Vs0HkOuH7ssGW68xXTYgyrcWElrYUJ1DFcix6Goj5Iy4dPaPwZ/Ihk= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zoho.com; s=zohoarc; t=1562030877; h=Content-Type: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=V7U61wfteYgTVrbu9ULhFYiEoSwSqbD5XERC66NXD/0=; b=SIWNETqpT2Wp3smO5V/yn3Dce4fVtaPbctej9M7E33Wndwc8pNJrAJIcKmRH8/SgAFjKtcVkfSWCegIvI7D2nNFWoQvkA+jZHwpzrxMC4mixHv4cpoj1RUAo3DJKv5XHmgmo8zS8/39r/P9wQKcBtLXiiSlovOp4uFPo6Fjz7s8= 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 156203087726534.25398749788087; Mon, 1 Jul 2019 18:27:57 -0700 (PDT) Received: from localhost ([::1]:46830 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.86_2) (envelope-from ) id 1hi7aM-0006gv-5m for importer@patchew.org; Mon, 01 Jul 2019 21:27:54 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:47114) by lists.gnu.org with esmtp (Exim 4.86_2) (envelope-from ) id 1hi3xK-0000gV-EM for qemu-devel@nongnu.org; Mon, 01 Jul 2019 17:35:23 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1hi3xI-0002Hl-4Q for qemu-devel@nongnu.org; Mon, 01 Jul 2019 17:35:22 -0400 Received: from mx1.redhat.com ([209.132.183.28]:46562) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1hi3xC-00029M-8Y; Mon, 01 Jul 2019 17:35:14 -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 A7BFE3082E72; Mon, 1 Jul 2019 19:50:17 +0000 (UTC) Received: from x1w.redhat.com (unknown [10.40.205.170]) by smtp.corp.redhat.com (Postfix) with ESMTPS id B8E0D379F; Mon, 1 Jul 2019 19:50:14 +0000 (UTC) From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= To: qemu-devel@nongnu.org Date: Mon, 1 Jul 2019 21:49:39 +0200 Message-Id: <20190701194942.10092-6-philmd@redhat.com> In-Reply-To: <20190701194942.10092-1-philmd@redhat.com> References: <20190701194942.10092-1-philmd@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.46]); Mon, 01 Jul 2019 19:50:17 +0000 (UTC) Content-Transfer-Encoding: quoted-printable X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] X-Received-From: 209.132.183.28 Subject: [Qemu-devel] [PATCH v4 5/8] RFC target/arm: Do not build pre-ARMv7 cpus when using KVM 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: Yang Zhong , Peter Maydell , Andrew Jones , Samuel Ortiz , Rob Bradford , =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= , Thomas Huth , qemu-arm@nongnu.org, Paolo Bonzini , =?UTF-8?q?Alex=20Benn=C3=A9e?= Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" Content-Type: text/plain; charset="utf-8" A KVM-only build won't be able to run pre-ARMv7 cpus, disable them. If KVM is not enabled, they are enabled by default. Signed-off-by: Philippe Mathieu-Daud=C3=A9 --- Sadly this does not work with --enable-tcg --enable-kvm dual config. --- default-configs/arm-softmmu.mak | 33 ++++++++++++++++----------------- hw/arm/Kconfig | 26 ++++++++++++++++++++++++++ 2 files changed, 42 insertions(+), 17 deletions(-) diff --git a/default-configs/arm-softmmu.mak b/default-configs/arm-softmmu.= mak index 1f2e0e7fde..081d507c87 100644 --- a/default-configs/arm-softmmu.mak +++ b/default-configs/arm-softmmu.mak @@ -9,34 +9,33 @@ CONFIG_ARM_V7M=3Dy CONFIG_ARM_VIRT=3Dy CONFIG_CUBIEBOARD=3Dy CONFIG_EXYNOS4=3Dy -CONFIG_HIGHBANK=3Dy -CONFIG_INTEGRATOR=3Dy CONFIG_FSL_IMX31=3Dy -CONFIG_MUSICPAL=3Dy CONFIG_MUSCA=3Dy -CONFIG_CHEETAH=3Dy -CONFIG_SX1=3Dy -CONFIG_NSERIES=3Dy CONFIG_STELLARIS=3Dy CONFIG_REALVIEW=3Dy -CONFIG_VERSATILE=3Dy CONFIG_VEXPRESS=3Dy CONFIG_ZYNQ=3Dy -CONFIG_MAINSTONE=3Dy -CONFIG_GUMSTIX=3Dy -CONFIG_SPITZ=3Dy -CONFIG_TOSA=3Dy -CONFIG_Z2=3Dy -CONFIG_COLLIE=3Dy -CONFIG_ASPEED_SOC=3Dy CONFIG_NETDUINO2=3Dy CONFIG_MPS2=3Dy CONFIG_RASPI=3Dy -CONFIG_DIGIC=3Dy CONFIG_SABRELITE=3Dy CONFIG_EMCRAFT_SF2=3Dy -CONFIG_MICROBIT=3Dy -CONFIG_FSL_IMX25=3Dy CONFIG_FSL_IMX7=3Dy CONFIG_FSL_IMX6UL=3Dy CONFIG_SEMIHOSTING=3Dy +#CONFIG_CHEETAH=3Dy +#CONFIG_SX1=3Dy +#CONFIG_DIGIC=3Dy +#CONFIG_INTEGRATOR=3Dy +#CONFIG_MUSICPAL=3Dy +#CONFIG_MAINSTONE=3Dy +#CONFIG_GUMSTIX=3Dy +#CONFIG_SPITZ=3Dy +#CONFIG_TOSA=3Dy +#CONFIG_COLLIE=3Dy +#CONFIG_VERSATILE=3Dy +#CONFIG_FSL_IMX25=3Dy +#CONFIG_ASPEED_SOC=3Dy +#CONFIG_NSERIES=3Dy +#CONFIG_HIGHBANK=3Dn +#CONFIG_MICROBIT=3Dn diff --git a/hw/arm/Kconfig b/hw/arm/Kconfig index ab65ecd216..b4d31c6026 100644 --- a/hw/arm/Kconfig +++ b/hw/arm/Kconfig @@ -1,3 +1,18 @@ +config ARM_V4 + default y + depends on !KVM + bool + +config ARM_V5 + default y + depends on !KVM + bool + +config ARM_V6 + default y + depends on !KVM + bool + config ARM_VIRT bool imply PCI_DEVICES @@ -23,6 +38,7 @@ config ARM_VIRT =20 config CHEETAH bool + select ARM_V4 select OMAP select TSC210X =20 @@ -32,6 +48,7 @@ config CUBIEBOARD =20 config DIGIC bool + select ARM_V5 select PTIMER select PFLASH_CFI02 =20 @@ -61,6 +78,7 @@ config HIGHBANK =20 config INTEGRATOR bool + select ARM_V5 select ARM_TIMER select INTEGRATOR_DEBUG select PL011 # UART @@ -84,6 +102,7 @@ config MUSCA =20 config MUSICPAL bool + select ARM_V5 select BITBANG_I2C select MARVELL_88W8618 select PTIMER @@ -97,6 +116,7 @@ config NETDUINO2 =20 config NSERIES bool + select ARM_V6 select OMAP select TMP105 # tempature sensor select BLIZZARD # LCD/TV controller @@ -119,6 +139,7 @@ config OMAP =20 config PXA2XX bool + select ARM_V5 select FRAMEBUFFER select I2C select SERIAL @@ -229,10 +250,12 @@ config COLLIE =20 config SX1 bool + select ARM_V4 select OMAP =20 config VERSATILE bool + select ARM_V5 select ARM_TIMER # sp804 select PFLASH_CFI01 select LSI_SCSI_PCI @@ -321,6 +344,7 @@ config XLNX_VERSAL =20 config FSL_IMX25 bool + select ARM_V5 select IMX select IMX_FEC select IMX_I2C @@ -328,6 +352,7 @@ config FSL_IMX25 =20 config FSL_IMX31 bool + select ARM_V6 select SERIAL select IMX select IMX_I2C @@ -343,6 +368,7 @@ config FSL_IMX6 =20 config ASPEED_SOC bool + select ARM_V5 select DS1338 select FTGMAC100 select I2C --=20 2.20.1 From nobody Mon May 13 12:20:01 2024 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=1562030900; cv=none; d=zoho.com; s=zohoarc; b=MPYOm/1EVh4V4HeTTEcjshMgt5wwtiq7GaGwPwTF5k/dRD0G4d4rmqfBvjuUH3+EwdPdfvtNn0xytAubNfCGIxJxScFgUD1cPBvtGj77/Ua2cXKPJVDrrmI6l+oIbV2RtrwhRIZD7ZDR4fpurVTs7irpc0TQTKMuqc4u51uN/J0= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zoho.com; s=zohoarc; t=1562030900; h=Content-Type: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=CnTlume30XjQNuzlTe5ksrWh9EW2DnkN5nXFnMrUK+Q=; b=hr5S/nid9DCLZOsHzQf/RuVODMePJSETYUG9/Rcf7R8i5YfnQIqodu74ecsaphfj/puiodgA9ORI4tN59xVOuhuau3Skd66CM1EF3WmmjRjrmaJhWaxoRc6Tz+8XI0U/pvX0updbHN/f3Mn60bqAGiK3+k06gU4xSGo3T4RGb64= 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 1562030900411909.6492471019201; Mon, 1 Jul 2019 18:28:20 -0700 (PDT) Received: from localhost ([::1]:46838 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.86_2) (envelope-from ) id 1hi7al-0007LN-Fx for importer@patchew.org; Mon, 01 Jul 2019 21:28:19 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:44739) by lists.gnu.org with esmtp (Exim 4.86_2) (envelope-from ) id 1hi3rd-0005Iv-DI for qemu-devel@nongnu.org; Mon, 01 Jul 2019 17:29:30 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1hi3rc-0008Rg-Ct for qemu-devel@nongnu.org; Mon, 01 Jul 2019 17:29:29 -0400 Received: from mx1.redhat.com ([209.132.183.28]:36895) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1hi3rZ-0008No-DL; Mon, 01 Jul 2019 17:29:25 -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 1F18630BBE98; Mon, 1 Jul 2019 19:50:21 +0000 (UTC) Received: from x1w.redhat.com (unknown [10.40.205.170]) by smtp.corp.redhat.com (Postfix) with ESMTPS id 2B6CF379F; Mon, 1 Jul 2019 19:50:17 +0000 (UTC) From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= To: qemu-devel@nongnu.org Date: Mon, 1 Jul 2019 21:49:40 +0200 Message-Id: <20190701194942.10092-7-philmd@redhat.com> In-Reply-To: <20190701194942.10092-1-philmd@redhat.com> References: <20190701194942.10092-1-philmd@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]); Mon, 01 Jul 2019 19:50:21 +0000 (UTC) Content-Transfer-Encoding: quoted-printable X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] X-Received-From: 209.132.183.28 Subject: [Qemu-devel] [PATCH v4 6/8] RFC target/arm: Restrict R and M profiles to TCG 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: Yang Zhong , Peter Maydell , Andrew Jones , Samuel Ortiz , Rob Bradford , =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= , Thomas Huth , qemu-arm@nongnu.org, Paolo Bonzini , =?UTF-8?q?Alex=20Benn=C3=A9e?= Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" Content-Type: text/plain; charset="utf-8" KVM is only able to run A profile cpus. Signed-off-by: Philippe Mathieu-Daud=C3=A9 --- target/arm/cpu.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/target/arm/cpu.c b/target/arm/cpu.c index 290ef16e52..a0934a47ee 100644 --- a/target/arm/cpu.c +++ b/target/arm/cpu.c @@ -453,7 +453,9 @@ bool arm_cpu_exec_interrupt(CPUState *cs, int interrupt= _request) return ret; } =20 -#if !defined(CONFIG_USER_ONLY) || !defined(TARGET_AARCH64) +/* CPU models. These are not needed for the AArch64 linux-user build. */ +#if (!defined(CONFIG_USER_ONLY) || !defined(TARGET_AARCH64)) \ + && defined(CONFIG_TCG) static bool arm_v7m_cpu_exec_interrupt(CPUState *cs, int interrupt_request) { CPUClass *cc =3D CPU_GET_CLASS(cs); @@ -1855,8 +1857,6 @@ static void cortex_m0_initfn(Object *obj) cpu->midr =3D 0x410cc200; } =20 -#endif - static void cortex_m3_initfn(Object *obj) { ARMCPU *cpu =3D ARM_CPU(obj); @@ -2010,6 +2010,8 @@ static void cortex_r5f_initfn(Object *obj) cpu->isar.mvfr1 =3D 0x00000011; } =20 +#endif + static const ARMCPRegInfo cortexa8_cp_reginfo[] =3D { { .name =3D "L2LOCKDOWN", .cp =3D 15, .crn =3D 9, .crm =3D 0, .opc1 = =3D 1, .opc2 =3D 0, .access =3D PL1_RW, .type =3D ARM_CP_CONST, .resetvalue =3D 0 }, @@ -2491,7 +2493,6 @@ static const ARMCPUInfo arm_cpus[] =3D { { .name =3D "arm1176", .initfn =3D arm1176_initfn }, { .name =3D "arm11mpcore", .initfn =3D arm11mpcore_initfn }, { .name =3D "cortex-m0", .initfn =3D cortex_m0_initfn, -#endif .class_init =3D arm_v7m_class_init }, { .name =3D "cortex-m3", .initfn =3D cortex_m3_initfn, .class_init =3D arm_v7m_class_init }, @@ -2501,6 +2502,7 @@ static const ARMCPUInfo arm_cpus[] =3D { .class_init =3D arm_v7m_class_init }, { .name =3D "cortex-r5", .initfn =3D cortex_r5_initfn }, { .name =3D "cortex-r5f", .initfn =3D cortex_r5f_initfn }, +#endif { .name =3D "cortex-a7", .initfn =3D cortex_a7_initfn }, { .name =3D "cortex-a8", .initfn =3D cortex_a8_initfn }, { .name =3D "cortex-a9", .initfn =3D cortex_a9_initfn }, --=20 2.20.1 From nobody Mon May 13 12:20:01 2024 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=1562019911; cv=none; d=zoho.com; s=zohoarc; b=dFdrOAO6lMpYTlXpKSwhsZvXII2djZYe+uRxP7ZQuh347QiCBA8p0rVlXcGoy7sl78TU6PMPoZT+Vz96ILjBrjeKRDk1aVsPfrETqPzRse8wDXRwczJ+7vA9SV16ebgBndGqdH6TG9fpQHRPsKY2iGX/FgIS7AZ7tIeeM25+KL0= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zoho.com; s=zohoarc; t=1562019911; h=Content-Type: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=9w8h84PBww/5FTh/NDyqVCXEt3ft0QlJG1ZC0kbXknw=; b=KMa+BOIjObBl9tJs3bXgFBKIMOKVdfWhK+zQITTgz5tryZz5XACSGo8QSyUH+SJQ8d0/j9LoiR/TcPZhq6yBAkpfPR74+jX4d97rT0qbupeCoiKkEcbMOpXeI0qGhlrZ9MYgYr23hrvPWipXJpXht1thJzjy++JX7gwOJejvXDw= 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 1562019911641778.0675317029039; Mon, 1 Jul 2019 15:25:11 -0700 (PDT) Received: from localhost ([::1]:46050 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.86_2) (envelope-from ) id 1hi4jU-0002MQ-2A for importer@patchew.org; Mon, 01 Jul 2019 18:25:08 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:56425) by lists.gnu.org with esmtp (Exim 4.86_2) (envelope-from ) id 1hi3XZ-00083Q-6I for qemu-devel@nongnu.org; Mon, 01 Jul 2019 17:08:46 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1hi3XY-0006UB-4W for qemu-devel@nongnu.org; Mon, 01 Jul 2019 17:08:45 -0400 Received: from mx1.redhat.com ([209.132.183.28]:11475) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1hi3XT-0006RA-OL; Mon, 01 Jul 2019 17:08:39 -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 B80E6223884; Mon, 1 Jul 2019 19:50:26 +0000 (UTC) Received: from x1w.redhat.com (unknown [10.40.205.170]) by smtp.corp.redhat.com (Postfix) with ESMTPS id 99A719089; Mon, 1 Jul 2019 19:50:21 +0000 (UTC) From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= To: qemu-devel@nongnu.org Date: Mon, 1 Jul 2019 21:49:41 +0200 Message-Id: <20190701194942.10092-8-philmd@redhat.com> In-Reply-To: <20190701194942.10092-1-philmd@redhat.com> References: <20190701194942.10092-1-philmd@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.39]); Mon, 01 Jul 2019 19:50:26 +0000 (UTC) Content-Transfer-Encoding: quoted-printable X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] X-Received-From: 209.132.183.28 Subject: [Qemu-devel] [PATCH v4 7/8] RFC target/arm: Do not build A/M-profile cpus when using KVM 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: Yang Zhong , Peter Maydell , Andrew Jones , Samuel Ortiz , Rob Bradford , =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= , Thomas Huth , qemu-arm@nongnu.org, Paolo Bonzini , =?UTF-8?q?Alex=20Benn=C3=A9e?= Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" Content-Type: text/plain; charset="utf-8" A KVM-only build won't be able to run A or M-profile cpus, disable them. If KVM is not enabled, they are enabled by default. Signed-off-by: Philippe Mathieu-Daud=C3=A9 --- Sadly this does not work with --enable-tcg --enable-kvm dual config. --- default-configs/arm-softmmu.mak | 14 ++++++-------- hw/arm/Kconfig | 16 +++++++++++++--- 2 files changed, 19 insertions(+), 11 deletions(-) diff --git a/default-configs/arm-softmmu.mak b/default-configs/arm-softmmu.= mak index 081d507c87..3995c4bb65 100644 --- a/default-configs/arm-softmmu.mak +++ b/default-configs/arm-softmmu.mak @@ -1,25 +1,18 @@ # Default configuration for arm-softmmu =20 -# TODO: ARM_V7M is currently always required - make this more flexible! -CONFIG_ARM_V7M=3Dy - # CONFIG_PCI_DEVICES=3Dn # CONFIG_TEST_DEVICES=3Dn +CONFIG_ARM_V7M=3Dn =20 CONFIG_ARM_VIRT=3Dy CONFIG_CUBIEBOARD=3Dy CONFIG_EXYNOS4=3Dy CONFIG_FSL_IMX31=3Dy -CONFIG_MUSCA=3Dy -CONFIG_STELLARIS=3Dy CONFIG_REALVIEW=3Dy CONFIG_VEXPRESS=3Dy CONFIG_ZYNQ=3Dy -CONFIG_NETDUINO2=3Dy -CONFIG_MPS2=3Dy CONFIG_RASPI=3Dy CONFIG_SABRELITE=3Dy -CONFIG_EMCRAFT_SF2=3Dy CONFIG_FSL_IMX7=3Dy CONFIG_FSL_IMX6UL=3Dy CONFIG_SEMIHOSTING=3Dy @@ -38,4 +31,9 @@ CONFIG_SEMIHOSTING=3Dy #CONFIG_ASPEED_SOC=3Dy #CONFIG_NSERIES=3Dy #CONFIG_HIGHBANK=3Dn +#CONFIG_MUSCA=3Dn +#CONFIG_STELLARIS=3Dn +#CONFIG_NETDUINO2=3Dn +#CONFIG_MPS2=3Dn +#CONFIG_EMCRAFT_SF2=3Dn #CONFIG_MICROBIT=3Dn diff --git a/hw/arm/Kconfig b/hw/arm/Kconfig index b4d31c6026..f8242068ad 100644 --- a/hw/arm/Kconfig +++ b/hw/arm/Kconfig @@ -13,6 +13,18 @@ config ARM_V6 depends on !KVM bool =20 +# ARM Microcontroller profile +config ARM_V7M + default y + depends on !KVM + bool + +# ARM Realtime profile +config ARM_V7R + default y + depends on !KVM + bool + config ARM_VIRT bool imply PCI_DEVICES @@ -295,9 +307,6 @@ config ZYNQ select XILINX_SPIPS select ZYNQ_DEVCFG =20 -config ARM_V7M - bool - config ALLWINNER_A10 bool select AHCI @@ -323,6 +332,7 @@ config STM32F205_SOC =20 config XLNX_ZYNQMP_ARM bool + select ARM_V7R select AHCI select ARM_GIC select CADENCE --=20 2.20.1 From nobody Mon May 13 12:20:01 2024 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=1562017487; cv=none; d=zoho.com; s=zohoarc; b=et4oGclYHO2x09aOFymvK1FarjF8rePRsjJsSuXbybronYTOHZmdbEQGAQ86ydcw7AaH/k7Y9m3SCod35sTvKHUctDw9OHVwtb4KBhf15bUZ/+5dCuXFYj2XWcFnj2WtpdNbzThkzMVXN0xEMW7KX6QXZTtBnpN/8MBB4Z/eWYE= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zoho.com; s=zohoarc; t=1562017487; h=Content-Type: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=LT4HpjXQP/owTstAVzvS27xB9rVGfS3RCqD1FOGAQXU=; b=DF6d6/+Tt4/0niVNmoDMJPy1tbkYQfqu/6IoEbRbN3qHHYlC58y0DsdwhGCZi/L+dnTHXJSf7xv7gGQGzfLg+zln9UYfweoKhfXNPT5oQCvxYzQ39szcUI1Skyz4ORsKmzTNIqKOgW08LcHozx5bNBI3EKVxmtqbliW6XGs+6eY= 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 1562017487758853.3920796236447; Mon, 1 Jul 2019 14:44:47 -0700 (PDT) Received: from localhost ([::1]:45766 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.86_2) (envelope-from ) id 1hi46Q-0002K1-NE for importer@patchew.org; Mon, 01 Jul 2019 17:44:46 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:54764) by lists.gnu.org with esmtp (Exim 4.86_2) (envelope-from ) id 1hi3WG-0006jM-Fd for qemu-devel@nongnu.org; Mon, 01 Jul 2019 17:07:25 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1hi3WF-0005bX-F6 for qemu-devel@nongnu.org; Mon, 01 Jul 2019 17:07:24 -0400 Received: from mx1.redhat.com ([209.132.183.28]:33562) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1hi3WC-0005Tw-AM; Mon, 01 Jul 2019 17:07:20 -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 3BC63308A963; Mon, 1 Jul 2019 19:50:32 +0000 (UTC) Received: from x1w.redhat.com (unknown [10.40.205.170]) by smtp.corp.redhat.com (Postfix) with ESMTPS id 34BF8379F; Mon, 1 Jul 2019 19:50:26 +0000 (UTC) From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= To: qemu-devel@nongnu.org Date: Mon, 1 Jul 2019 21:49:42 +0200 Message-Id: <20190701194942.10092-9-philmd@redhat.com> In-Reply-To: <20190701194942.10092-1-philmd@redhat.com> References: <20190701194942.10092-1-philmd@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.41]); Mon, 01 Jul 2019 19:50:32 +0000 (UTC) Content-Transfer-Encoding: quoted-printable X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] X-Received-From: 209.132.183.28 Subject: [Qemu-devel] [PATCH v4 8/8] target/arm: Do not build TCG objects when TCG is off 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: Yang Zhong , Peter Maydell , Andrew Jones , Samuel Ortiz , Rob Bradford , =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= , Thomas Huth , qemu-arm@nongnu.org, Paolo Bonzini , =?UTF-8?q?Alex=20Benn=C3=A9e?= Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" Content-Type: text/plain; charset="utf-8" We can now safely turn all TCG dependent build off when CONFIG_TCG is off. This allows building ARM binaries with --disable-tcg. Signed-off-by: Samuel Ortiz Signed-off-by: Philippe Mathieu-Daud=C3=A9 --- v3: complete rewrite of patch content, removed R-b tags --- target/arm/Makefile.objs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/target/arm/Makefile.objs b/target/arm/Makefile.objs index 89cd7c36e3..c8bca74a63 100644 --- a/target/arm/Makefile.objs +++ b/target/arm/Makefile.objs @@ -32,6 +32,8 @@ target/arm/translate-sve.o: target/arm/decode-sve.inc.c target/arm/translate.o: target/arm/decode-vfp.inc.c target/arm/translate.o: target/arm/decode-vfp-uncond.inc.c =20 +ifeq ($(CONFIG_TCG),y) + obj-y +=3D tlb_helper.o debug_helper.o obj-y +=3D translate.o op_helper.o obj-y +=3D crypto_helper.o @@ -43,3 +45,5 @@ obj-$(CONFIG_SOFTMMU) +=3D psci.o obj-$(TARGET_AARCH64) +=3D translate-a64.o helper-a64.o obj-$(TARGET_AARCH64) +=3D translate-sve.o sve_helper.o obj-$(TARGET_AARCH64) +=3D pauth_helper.o + +endif # CONFIG_TCG --=20 2.20.1