qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
* [Qemu-devel] [PATCH v2 00/23] Support disabling TCG on ARM
@ 2019-06-15 15:43 Philippe Mathieu-Daudé
  2019-06-15 15:43 ` [Qemu-devel] [PATCH v2 01/23] target/arm: Makefile cleanup (Aarch64) Philippe Mathieu-Daudé
                   ` (22 more replies)
  0 siblings, 23 replies; 51+ messages in thread
From: Philippe Mathieu-Daudé @ 2019-06-15 15:43 UTC (permalink / raw)
  To: qemu-devel; +Cc: Peter Maydell, qemu-arm, Philippe Mathieu-Daudé

Paolo motived me to salvage this (other!) previous series fromi
Samuel Ortiz (NEMU project).

v1 cover from Samuel [1]:

  This patchset allows for building and running ARM targets with TCG
  disabled. It splits the target/arm/helper.c file into logical TCG and
  non TCG dependent files so that one can build and run QEMU binaries with
  or without TCG enabled.

  The rationale behind this work comes from the NEMU project where we're
  trying to only support x86 and ARM 64-bit architectures, without
  including the TCG code base. We can only do so if we can build and run
  ARM binaries with TCG disabled.

v2:

Most of the patches from v1 got adapted, except the "Move all
interrupt handlers" patch, because Peter disagreed with it.
See threads:
 https://lists.gnu.org/archive/html/qemu-devel/2018-11/msg03908.html
 https://lists.gnu.org/archive/html/qemu-devel/2019-05/msg07304.html
Anyway this is not a blocking issue, and can be done once this series
get merged.

This is a kind of series you don't want to rebase (as in, the quicker
it get merged, the saner). It is also one of my most painful QEMU
series, and really wish it was worthwhile.

The diffstat is pretty decent.

Regards,

Phil.

[1]: https://lists.gnu.org/archive/html/qemu-devel/2018-11/msg02451.html

Philippe Mathieu-Daudé (15):
  target/arm: Makefile cleanup (Aarch64)
  target/arm: Makefile cleanup (ARM)
  target/arm: Makefile cleanup (KVM)
  target/arm: Makefile cleanup (softmmu)
  target/arm: Add copyright boilerplate
  target/arm: Fix multiline comment syntax
  target/arm: Declare some function publicly
  target/arm: Move code around
  target/arm: Move the v7-M Security State helpers to v7m_helper
  target/arm: Declare v7m_cpacr_pass() publicly
  target/arm: Make the v7-M Security State routines static
  target/arm: Make arm_deliver_fault() static
  target/arm: Fix coding style issues
  target/arm: Restrict semi-hosting to TCG
  target/arm: Missing symbols when building with --disable-tcg

Samuel Ortiz (8):
  target/arm: Move all v7m insn helpers into their own file
  target/arm: Move v7m exception handling routines to v7m_helper
  target/arm: Move the DC ZVA helper into op_helper
  target/arm: Make ARM TLB filling routine static
  target/arm: Move CPU state dumping routines to helper.c
  target/arm: Move watchpoints APIs to helper.c
  target/arm: Define TCG dependent functions when TCG is enabled
  target/arm: Do not build TCG objects when TCG is off

 target/arm/Makefile.objs   |   25 +-
 target/arm/cpu.c           |    8 +-
 target/arm/helper.c        | 3416 ++++++------------------------------
 target/arm/internals.h     |   77 +-
 target/arm/kvm-missing.c   |   22 +
 target/arm/op_helper.c     |  358 ++--
 target/arm/translate-a64.c |  127 --
 target/arm/translate.c     |   90 +-
 target/arm/translate.h     |    5 -
 target/arm/v7m_helper.c    | 2603 +++++++++++++++++++++++++++
 10 files changed, 3451 insertions(+), 3280 deletions(-)
 create mode 100644 target/arm/kvm-missing.c
 create mode 100644 target/arm/v7m_helper.c

-- 
2.20.1



^ permalink raw reply	[flat|nested] 51+ messages in thread

* [Qemu-devel] [PATCH v2 01/23] target/arm: Makefile cleanup (Aarch64)
  2019-06-15 15:43 [Qemu-devel] [PATCH v2 00/23] Support disabling TCG on ARM Philippe Mathieu-Daudé
@ 2019-06-15 15:43 ` Philippe Mathieu-Daudé
  2019-06-17 11:36   ` [Qemu-devel] [Qemu-arm] " Alex Bennée
  2019-06-15 15:43 ` [Qemu-devel] [PATCH v2 02/23] target/arm: Makefile cleanup (ARM) Philippe Mathieu-Daudé
                   ` (21 subsequent siblings)
  22 siblings, 1 reply; 51+ messages in thread
From: Philippe Mathieu-Daudé @ 2019-06-15 15:43 UTC (permalink / raw)
  To: qemu-devel; +Cc: Peter Maydell, qemu-arm, Philippe Mathieu-Daudé

Group Aarch64 objects together, TCG related ones at the bottom.
This will help when restricting TCG-only objects.

Signed-off-by: Philippe Mathieu-Daudé <philmd@redhat.com>
---
 target/arm/Makefile.objs | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/target/arm/Makefile.objs b/target/arm/Makefile.objs
index dfa736a375..7c31fa01c1 100644
--- a/target/arm/Makefile.objs
+++ b/target/arm/Makefile.objs
@@ -7,8 +7,7 @@ obj-$(call lnot,$(CONFIG_KVM)) += kvm-stub.o
 obj-y += translate.o op_helper.o helper.o cpu.o
 obj-y += neon_helper.o iwmmxt_helper.o vec_helper.o vfp_helper.o
 obj-y += gdbstub.o
-obj-$(TARGET_AARCH64) += cpu64.o translate-a64.o helper-a64.o gdbstub64.o
-obj-$(TARGET_AARCH64) += pauth_helper.o
+obj-$(TARGET_AARCH64) += cpu64.o gdbstub64.o
 obj-y += crypto_helper.o
 obj-$(CONFIG_SOFTMMU) += arm-powerctl.o
 
@@ -33,4 +32,6 @@ 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
 
+obj-$(TARGET_AARCH64) += translate-a64.o helper-a64.o
 obj-$(TARGET_AARCH64) += translate-sve.o sve_helper.o
+obj-$(TARGET_AARCH64) += pauth_helper.o
-- 
2.20.1



^ permalink raw reply related	[flat|nested] 51+ messages in thread

* [Qemu-devel] [PATCH v2 02/23] target/arm: Makefile cleanup (ARM)
  2019-06-15 15:43 [Qemu-devel] [PATCH v2 00/23] Support disabling TCG on ARM Philippe Mathieu-Daudé
  2019-06-15 15:43 ` [Qemu-devel] [PATCH v2 01/23] target/arm: Makefile cleanup (Aarch64) Philippe Mathieu-Daudé
@ 2019-06-15 15:43 ` Philippe Mathieu-Daudé
  2019-06-17 11:36   ` [Qemu-devel] [Qemu-arm] " Alex Bennée
  2019-06-17 11:37   ` Alex Bennée
  2019-06-15 15:43 ` [Qemu-devel] [PATCH v2 03/23] target/arm: Makefile cleanup (KVM) Philippe Mathieu-Daudé
                   ` (20 subsequent siblings)
  22 siblings, 2 replies; 51+ messages in thread
From: Philippe Mathieu-Daudé @ 2019-06-15 15:43 UTC (permalink / raw)
  To: qemu-devel; +Cc: Peter Maydell, qemu-arm, Philippe Mathieu-Daudé

Group ARM objects together, TCG related ones at the bottom.
This will help when restricting TCG-only objects.

Signed-off-by: Philippe Mathieu-Daudé <philmd@redhat.com>
---
 target/arm/Makefile.objs | 9 ++++++---
 1 file changed, 6 insertions(+), 3 deletions(-)

diff --git a/target/arm/Makefile.objs b/target/arm/Makefile.objs
index 7c31fa01c1..3269dda613 100644
--- a/target/arm/Makefile.objs
+++ b/target/arm/Makefile.objs
@@ -4,11 +4,9 @@ obj-$(CONFIG_KVM) += kvm.o
 obj-$(call land,$(CONFIG_KVM),$(call lnot,$(TARGET_AARCH64))) += kvm32.o
 obj-$(call land,$(CONFIG_KVM),$(TARGET_AARCH64)) += kvm64.o
 obj-$(call lnot,$(CONFIG_KVM)) += kvm-stub.o
-obj-y += translate.o op_helper.o helper.o cpu.o
-obj-y += neon_helper.o iwmmxt_helper.o vec_helper.o vfp_helper.o
+obj-y += helper.o cpu.o
 obj-y += gdbstub.o
 obj-$(TARGET_AARCH64) += cpu64.o gdbstub64.o
-obj-y += crypto_helper.o
 obj-$(CONFIG_SOFTMMU) += arm-powerctl.o
 
 DECODETREE = $(SRC_PATH)/scripts/decodetree.py
@@ -32,6 +30,11 @@ 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
 
+obj-y += translate.o op_helper.o
+obj-y += crypto_helper.o
+obj-y += iwmmxt_helper.o vec_helper.o
+obj-y += neon_helper.o vfp_helper.o
+
 obj-$(TARGET_AARCH64) += translate-a64.o helper-a64.o
 obj-$(TARGET_AARCH64) += translate-sve.o sve_helper.o
 obj-$(TARGET_AARCH64) += pauth_helper.o
-- 
2.20.1



^ permalink raw reply related	[flat|nested] 51+ messages in thread

* [Qemu-devel] [PATCH v2 03/23] target/arm: Makefile cleanup (KVM)
  2019-06-15 15:43 [Qemu-devel] [PATCH v2 00/23] Support disabling TCG on ARM Philippe Mathieu-Daudé
  2019-06-15 15:43 ` [Qemu-devel] [PATCH v2 01/23] target/arm: Makefile cleanup (Aarch64) Philippe Mathieu-Daudé
  2019-06-15 15:43 ` [Qemu-devel] [PATCH v2 02/23] target/arm: Makefile cleanup (ARM) Philippe Mathieu-Daudé
@ 2019-06-15 15:43 ` Philippe Mathieu-Daudé
  2019-06-17 11:37   ` [Qemu-devel] [Qemu-arm] " Alex Bennée
  2019-06-15 15:43 ` [Qemu-devel] [PATCH v2 04/23] target/arm: Makefile cleanup (softmmu) Philippe Mathieu-Daudé
                   ` (19 subsequent siblings)
  22 siblings, 1 reply; 51+ messages in thread
From: Philippe Mathieu-Daudé @ 2019-06-15 15:43 UTC (permalink / raw)
  To: qemu-devel; +Cc: Peter Maydell, qemu-arm, Philippe Mathieu-Daudé

Group KVM objects together.

Signed-off-by: Philippe Mathieu-Daudé <philmd@redhat.com>
---
 target/arm/Makefile.objs | 9 +++++----
 1 file changed, 5 insertions(+), 4 deletions(-)

diff --git a/target/arm/Makefile.objs b/target/arm/Makefile.objs
index 3269dda613..626e340f55 100644
--- a/target/arm/Makefile.objs
+++ b/target/arm/Makefile.objs
@@ -1,14 +1,15 @@
 obj-y += arm-semi.o
 obj-$(CONFIG_SOFTMMU) += machine.o psci.o arch_dump.o monitor.o
-obj-$(CONFIG_KVM) += kvm.o
-obj-$(call land,$(CONFIG_KVM),$(call lnot,$(TARGET_AARCH64))) += kvm32.o
-obj-$(call land,$(CONFIG_KVM),$(TARGET_AARCH64)) += kvm64.o
-obj-$(call lnot,$(CONFIG_KVM)) += kvm-stub.o
 obj-y += helper.o cpu.o
 obj-y += gdbstub.o
 obj-$(TARGET_AARCH64) += cpu64.o gdbstub64.o
 obj-$(CONFIG_SOFTMMU) += arm-powerctl.o
 
+obj-$(CONFIG_KVM) += kvm.o
+obj-$(call land,$(CONFIG_KVM),$(call lnot,$(TARGET_AARCH64))) += kvm32.o
+obj-$(call land,$(CONFIG_KVM),$(TARGET_AARCH64)) += kvm64.o
+obj-$(call lnot,$(CONFIG_KVM)) += kvm-stub.o
+
 DECODETREE = $(SRC_PATH)/scripts/decodetree.py
 
 target/arm/decode-sve.inc.c: $(SRC_PATH)/target/arm/sve.decode $(DECODETREE)
-- 
2.20.1



^ permalink raw reply related	[flat|nested] 51+ messages in thread

* [Qemu-devel] [PATCH v2 04/23] target/arm: Makefile cleanup (softmmu)
  2019-06-15 15:43 [Qemu-devel] [PATCH v2 00/23] Support disabling TCG on ARM Philippe Mathieu-Daudé
                   ` (2 preceding siblings ...)
  2019-06-15 15:43 ` [Qemu-devel] [PATCH v2 03/23] target/arm: Makefile cleanup (KVM) Philippe Mathieu-Daudé
@ 2019-06-15 15:43 ` Philippe Mathieu-Daudé
  2019-06-17 11:38   ` [Qemu-devel] [Qemu-arm] " Alex Bennée
  2019-06-15 15:43 ` [Qemu-devel] [PATCH v2 05/23] target/arm: Add copyright boilerplate Philippe Mathieu-Daudé
                   ` (18 subsequent siblings)
  22 siblings, 1 reply; 51+ messages in thread
From: Philippe Mathieu-Daudé @ 2019-06-15 15:43 UTC (permalink / raw)
  To: qemu-devel; +Cc: Peter Maydell, qemu-arm, Philippe Mathieu-Daudé

Group SOFTMMU objects together.

Signed-off-by: Philippe Mathieu-Daudé <philmd@redhat.com>
---
 target/arm/Makefile.objs | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/target/arm/Makefile.objs b/target/arm/Makefile.objs
index 626e340f55..72b42f825f 100644
--- a/target/arm/Makefile.objs
+++ b/target/arm/Makefile.objs
@@ -1,9 +1,9 @@
 obj-y += arm-semi.o
-obj-$(CONFIG_SOFTMMU) += machine.o psci.o arch_dump.o monitor.o
-obj-y += helper.o cpu.o
-obj-y += gdbstub.o
+obj-y += cpu.o helper.o gdbstub.o
 obj-$(TARGET_AARCH64) += cpu64.o gdbstub64.o
-obj-$(CONFIG_SOFTMMU) += arm-powerctl.o
+
+obj-$(CONFIG_SOFTMMU) += machine.o arch_dump.o monitor.o arm-powerctl.o
+obj-$(CONFIG_SOFTMMU) += psci.o
 
 obj-$(CONFIG_KVM) += kvm.o
 obj-$(call land,$(CONFIG_KVM),$(call lnot,$(TARGET_AARCH64))) += kvm32.o
-- 
2.20.1



^ permalink raw reply related	[flat|nested] 51+ messages in thread

* [Qemu-devel] [PATCH v2 05/23] target/arm: Add copyright boilerplate
  2019-06-15 15:43 [Qemu-devel] [PATCH v2 00/23] Support disabling TCG on ARM Philippe Mathieu-Daudé
                   ` (3 preceding siblings ...)
  2019-06-15 15:43 ` [Qemu-devel] [PATCH v2 04/23] target/arm: Makefile cleanup (softmmu) Philippe Mathieu-Daudé
@ 2019-06-15 15:43 ` Philippe Mathieu-Daudé
  2019-06-17 11:39   ` [Qemu-devel] [Qemu-arm] " Alex Bennée
  2019-06-15 15:43 ` [Qemu-devel] [PATCH v2 06/23] target/arm: Fix multiline comment syntax Philippe Mathieu-Daudé
                   ` (17 subsequent siblings)
  22 siblings, 1 reply; 51+ messages in thread
From: Philippe Mathieu-Daudé @ 2019-06-15 15:43 UTC (permalink / raw)
  To: qemu-devel
  Cc: Peter Maydell, qemu-arm, Philippe Mathieu-Daudé,
	Samuel Ortiz, Robert Bradford

Signed-off-by: Philippe Mathieu-Daudé <philmd@redhat.com>
Reviewed-by: Robert Bradford <robert.bradford@intel.com>
Reviewed-by: Samuel Ortiz <sameo@linux.intel.com>
---
 target/arm/helper.c | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/target/arm/helper.c b/target/arm/helper.c
index df4276f5f6..d3f3cb57d5 100644
--- a/target/arm/helper.c
+++ b/target/arm/helper.c
@@ -1,3 +1,10 @@
+/*
+ * 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"
-- 
2.20.1



^ permalink raw reply related	[flat|nested] 51+ messages in thread

* [Qemu-devel] [PATCH v2 06/23] target/arm: Fix multiline comment syntax
  2019-06-15 15:43 [Qemu-devel] [PATCH v2 00/23] Support disabling TCG on ARM Philippe Mathieu-Daudé
                   ` (4 preceding siblings ...)
  2019-06-15 15:43 ` [Qemu-devel] [PATCH v2 05/23] target/arm: Add copyright boilerplate Philippe Mathieu-Daudé
@ 2019-06-15 15:43 ` Philippe Mathieu-Daudé
  2019-06-17 11:40   ` [Qemu-devel] [Qemu-arm] " Alex Bennée
  2019-06-15 15:43 ` [Qemu-devel] [PATCH v2 07/23] target/arm: Declare some function publicly Philippe Mathieu-Daudé
                   ` (16 subsequent siblings)
  22 siblings, 1 reply; 51+ messages in thread
From: Philippe Mathieu-Daudé @ 2019-06-15 15:43 UTC (permalink / raw)
  To: qemu-devel; +Cc: Peter Maydell, qemu-arm, Philippe Mathieu-Daudé

Since commit 8c06fbdf36b checkpatch.pl enforce a new multiline
comment syntax. Since we'll move this code around, fix its style
first.

Signed-off-by: Philippe Mathieu-Daudé <philmd@redhat.com>
---
 target/arm/helper.c    | 213 +++++++++++++++++++++++++++--------------
 target/arm/op_helper.c |  27 ++++--
 2 files changed, 160 insertions(+), 80 deletions(-)

diff --git a/target/arm/helper.c b/target/arm/helper.c
index d3f3cb57d5..9a3766b759 100644
--- a/target/arm/helper.c
+++ b/target/arm/helper.c
@@ -7531,7 +7531,8 @@ void HELPER(v7m_vlldm)(CPUARMState *env, uint32_t fptr)
 
 uint32_t HELPER(v7m_tt)(CPUARMState *env, uint32_t addr, uint32_t op)
 {
-    /* The TT instructions can be used by unprivileged code, but in
+    /*
+     * 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
@@ -7803,7 +7804,8 @@ static bool v7m_stack_write(ARMCPU *cpu, uint32_t addr, uint32_t value,
     return true;
 
 pend_fault:
-    /* By pending the exception at this point we are making
+    /*
+     * 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
@@ -7878,7 +7880,8 @@ static bool v7m_stack_read(ARMCPU *cpu, uint32_t *dest, uint32_t addr,
     return true;
 
 pend_fault:
-    /* By pending the exception at this point we are making
+    /*
+     * 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
@@ -7979,7 +7982,8 @@ void HELPER(v7m_preserve_fp_state)(CPUARMState *env)
      */
 }
 
-/* Write to v7M CONTROL.SPSEL bit for the specified security bank.
+/*
+ * 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.
@@ -8007,7 +8011,8 @@ static void write_v7m_control_spsel_for_secstate(CPUARMState *env,
     }
 }
 
-/* Write to v7M CONTROL.SPSEL bit. This may change the current
+/*
+ * 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)
@@ -8017,7 +8022,8 @@ static void write_v7m_control_spsel(CPUARMState *env, bool new_spsel)
 
 void write_v7m_exception(CPUARMState *env, uint32_t new_exc)
 {
-    /* Write a new value to v7m.exception, thus transitioning into or out
+    /*
+     * Write a new value to v7m.exception, thus transitioning into or out
      * of Handler mode; this may result in a change of active stack pointer.
      */
     bool new_is_psp, old_is_psp = v7m_using_psp(env);
@@ -8043,7 +8049,8 @@ static void switch_v7m_security_state(CPUARMState *env, bool new_secstate)
         return;
     }
 
-    /* All the banked state is accessed by looking at env->v7m.secure
+    /*
+     * All the banked state is accessed by looking at env->v7m.secure
      * except for the stack pointer; rearrange the SP appropriately.
      */
     new_ss_msp = env->v7m.other_ss_msp;
@@ -8070,7 +8077,8 @@ static void switch_v7m_security_state(CPUARMState *env, bool new_secstate)
 
 void HELPER(v7m_bxns)(CPUARMState *env, uint32_t dest)
 {
-    /* Handle v7M BXNS:
+    /*
+     * 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
      */
@@ -8085,7 +8093,8 @@ void HELPER(v7m_bxns)(CPUARMState *env, uint32_t dest)
     }
 
     if (dest >= min_magic) {
-        /* This is an exception return magic value; put it where
+        /*
+         * 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 complete"
@@ -8110,7 +8119,8 @@ void HELPER(v7m_bxns)(CPUARMState *env, uint32_t dest)
 
 void HELPER(v7m_blxns)(CPUARMState *env, uint32_t dest)
 {
-    /* Handle v7M BLXNS:
+    /*
+     * Handle v7M BLXNS:
      *  - bit 0 of the destination address is the target security state
      */
 
@@ -8123,7 +8133,8 @@ void HELPER(v7m_blxns)(CPUARMState *env, uint32_t dest)
     assert(env->v7m.secure);
 
     if (dest & 1) {
-        /* target is Secure, so this is just a normal BLX,
+        /*
+         * Target is Secure, so this is just a normal BLX,
          * except that the low bit doesn't indicate Thumb/not.
          */
         env->regs[14] = nextinst;
@@ -8154,7 +8165,8 @@ void HELPER(v7m_blxns)(CPUARMState *env, uint32_t dest)
     env->regs[13] = sp;
     env->regs[14] = 0xfeffffff;
     if (arm_v7m_is_handler_mode(env)) {
-        /* Write a dummy value to IPSR, to avoid leaking the current secure
+        /*
+         * 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.
          */
@@ -8169,7 +8181,8 @@ void HELPER(v7m_blxns)(CPUARMState *env, uint32_t dest)
 static uint32_t *get_v7m_sp_ptr(CPUARMState *env, bool secure, bool threadmode,
                                 bool spsel)
 {
-    /* Return a pointer to the location where we currently store the
+    /*
+     * 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
@@ -8215,7 +8228,8 @@ static bool arm_v7m_load_vector(ARMCPU *cpu, int exc, bool targets_secure,
 
     mmu_idx = 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
+    /*
+     * 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()
@@ -8246,7 +8260,8 @@ static bool arm_v7m_load_vector(ARMCPU *cpu, int exc, bool targets_secure,
     return true;
 
 load_fail:
-    /* All vector table fetch fails are reported as HardFault, with
+    /*
+     * 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,
@@ -8278,7 +8293,8 @@ static uint32_t v7m_integrity_sig(CPUARMState *env, uint32_t lr)
 static bool v7m_push_callee_stack(ARMCPU *cpu, uint32_t lr, bool dotailchain,
                                   bool ignore_faults)
 {
-    /* For v8M, push the callee-saves register part of the stack frame.
+    /*
+     * 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.
      */
@@ -8329,7 +8345,8 @@ static bool v7m_push_callee_stack(ARMCPU *cpu, uint32_t lr, bool dotailchain,
         return true;
     }
 
-    /* Write as much of the stack frame as we can. A write failure may
+    /*
+     * Write as much of the stack frame as we can. A write failure may
      * cause us to pend a derived exception.
      */
     sig = v7m_integrity_sig(env, lr);
@@ -8353,7 +8370,8 @@ static bool v7m_push_callee_stack(ARMCPU *cpu, uint32_t lr, bool dotailchain,
 static void v7m_exception_taken(ARMCPU *cpu, uint32_t lr, bool dotailchain,
                                 bool ignore_stackfaults)
 {
-    /* Do the "take the exception" parts of exception entry,
+    /*
+     * 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.
      */
@@ -8378,13 +8396,15 @@ static void v7m_exception_taken(ARMCPU *cpu, uint32_t lr, bool dotailchain,
     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
+            /*
+             * 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
+                    /*
+                     * 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
@@ -8393,7 +8413,8 @@ static void v7m_exception_taken(ARMCPU *cpu, uint32_t lr, bool dotailchain,
                     lr &= ~R_V7M_EXCRET_DCRS_MASK;
                 }
             } else {
-                /* We're going to a non-secure exception; push the
+                /*
+                 * We're going to a non-secure exception; push the
                  * callee-saves registers to the stack now, if they're
                  * not already saved.
                  */
@@ -8415,14 +8436,16 @@ static void v7m_exception_taken(ARMCPU *cpu, uint32_t lr, bool dotailchain,
             lr |= R_V7M_EXCRET_SPSEL_MASK;
         }
 
-        /* Clear registers if necessary to prevent non-secure exception
+        /*
+         * 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
+                /*
+                 * 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
@@ -8443,7 +8466,8 @@ static void v7m_exception_taken(ARMCPU *cpu, uint32_t lr, bool dotailchain,
     }
 
     if (push_failed && !ignore_stackfaults) {
-        /* Derived exception on callee-saves register stacking:
+        /*
+         * 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.
          */
@@ -8460,7 +8484,8 @@ static void v7m_exception_taken(ARMCPU *cpu, uint32_t lr, bool dotailchain,
         return;
     }
 
-    /* Now we've done everything that might cause a derived exception
+    /*
+     * 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).
      */
@@ -8663,7 +8688,8 @@ void HELPER(v7m_vlldm)(CPUARMState *env, uint32_t fptr)
 
 static bool v7m_push_stack(ARMCPU *cpu)
 {
-    /* Do the "set up stack frame" part of exception entry,
+    /*
+     * 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
@@ -8731,7 +8757,8 @@ static bool v7m_push_stack(ARMCPU *cpu)
         }
     }
 
-    /* Write as much of the stack frame as we can. If we fail a stack
+    /*
+     * 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).
@@ -8848,7 +8875,8 @@ static void do_v7m_exception_exit(ARMCPU *cpu)
     bool ftype;
     bool restore_s16_s31;
 
-    /* If we're not in Handler mode then jumps to magic exception-exit
+    /*
+     * 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
@@ -8862,7 +8890,8 @@ static void do_v7m_exception_exit(ARMCPU *cpu)
         return;
     }
 
-    /* In the spec pseudocode ExceptionReturn() is called directly
+    /*
+     * 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
@@ -8895,7 +8924,8 @@ static void do_v7m_exception_exit(ARMCPU *cpu)
     }
 
     if (arm_feature(env, ARM_FEATURE_M_SECURITY)) {
-        /* EXC_RETURN.ES validation check (R_SMFL). We must do this before
+        /*
+         * EXC_RETURN.ES validation check (R_SMFL). We must do this before
          * we pick which FAULTMASK to clear.
          */
         if (!env->v7m.secure &&
@@ -8909,7 +8939,8 @@ static void do_v7m_exception_exit(ARMCPU *cpu)
     }
 
     if (env->v7m.exception != ARMV7M_EXCP_NMI) {
-        /* Auto-clear FAULTMASK on return from other than 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 >= 0; the
          * value of the ES bit in the exception return value indicates
@@ -8934,7 +8965,8 @@ static void do_v7m_exception_exit(ARMCPU *cpu)
         /* still an irq active now */
         break;
     case 1:
-        /* we returned to base exception level, no nesting.
+        /*
+         * We returned to base exception level, no nesting.
          * (In the pseudocode this is written using "NestedActivation != 1"
          * where we have 'rettobase == false'.)
          */
@@ -8951,7 +8983,8 @@ static void do_v7m_exception_exit(ARMCPU *cpu)
 
     if (arm_feature(env, ARM_FEATURE_V8)) {
         if (!arm_feature(env, ARM_FEATURE_M_SECURITY)) {
-            /* UNPREDICTABLE if S == 1 or DCRS == 0 or ES == 1 (R_XLCP);
+            /*
+             * UNPREDICTABLE if S == 1 or DCRS == 0 or ES == 1 (R_XLCP);
              * we choose to take the UsageFault.
              */
             if ((excret & R_V7M_EXCRET_S_MASK) ||
@@ -8970,7 +9003,8 @@ static void do_v7m_exception_exit(ARMCPU *cpu)
             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
+            /*
+             * We only need to check NONBASETHRDENA for v7M, because in
              * v8M this bit does not exist (it is RES1).
              */
             if (!rettobase &&
@@ -9028,7 +9062,8 @@ static void do_v7m_exception_exit(ARMCPU *cpu)
     }
 
     if (ufault) {
-        /* Bad exception return: instead of popping the exception
+        /*
+         * Bad exception return: instead of popping the exception
          * stack, directly take a usage fault on the current stack.
          */
         env->v7m.cfsr[env->v7m.secure] |= R_V7M_CFSR_INVPC_MASK;
@@ -9058,7 +9093,8 @@ static void do_v7m_exception_exit(ARMCPU *cpu)
     switch_v7m_security_state(env, return_to_secure);
 
     {
-        /* The stack pointer we should be reading the exception frame from
+        /*
+         * 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
@@ -9131,7 +9167,8 @@ static void do_v7m_exception_exit(ARMCPU *cpu)
             v7m_stack_read(cpu, &xpsr, frameptr + 0x1c, mmu_idx);
 
         if (!pop_ok) {
-            /* v7m_stack_read() pended a fault, so take it (as a tail
+            /*
+             * 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");
@@ -9139,7 +9176,8 @@ static void do_v7m_exception_exit(ARMCPU *cpu)
             return;
         }
 
-        /* Returning from an exception with a PC with bit 0 set is defined
+        /*
+         * 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 specified
          * to be UNPREDICTABLE. In practice actual v7M hardware seems to ignore
          * the lsbit, and there are several RTOSes out there which incorrectly
@@ -9157,13 +9195,15 @@ static void do_v7m_exception_exit(ARMCPU *cpu)
         }
 
         if (arm_feature(env, ARM_FEATURE_V8)) {
-            /* For v8M we have to check whether the xPSR exception field
+            /*
+             * 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 = (xpsr & XPSR_EXCP) != 0;
             if (return_to_handler != will_be_handler) {
-                /* Take an INVPC UsageFault on the current stack.
+                /*
+                 * Take an INVPC UsageFault on the current stack.
                  * By this point we will have switched to the security state
                  * for the background state, so this UsageFault will target
                  * that state.
@@ -9278,7 +9318,8 @@ static void do_v7m_exception_exit(ARMCPU *cpu)
                 frameptr += 0x40;
             }
         }
-        /* Undo stack alignment (the SPREALIGN bit indicates that the original
+        /*
+         * Undo stack alignment (the SPREALIGN bit indicates that the original
          * 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. (Adding 4
@@ -9304,13 +9345,15 @@ static void do_v7m_exception_exit(ARMCPU *cpu)
                                                V7M_CONTROL, SFPA, sfpa);
     }
 
-    /* The restored xPSR exception field will be zero if we're
+    /*
+     * 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 != arm_v7m_is_handler_mode(env)) {
-        /* Take an INVPC UsageFault by pushing the stack again;
+        /*
+         * Take an INVPC UsageFault by pushing the stack again;
          * we know we're v7M so this is never a Secure UsageFault.
          */
         bool ignore_stackfaults;
@@ -9332,7 +9375,8 @@ static void do_v7m_exception_exit(ARMCPU *cpu)
 
 static bool do_v7m_function_return(ARMCPU *cpu)
 {
-    /* v8M security extensions magic function return.
+    /*
+     * v8M security extensions magic function return.
      * We may either:
      *  (1) throw an exception (longjump)
      *  (2) return true if we successfully handled the function return
@@ -9362,7 +9406,8 @@ static bool do_v7m_function_return(ARMCPU *cpu)
         frame_sp_p = get_v7m_sp_ptr(env, true, threadmode, spsel);
         frameptr = *frame_sp_p;
 
-        /* These loads may throw an exception (for MPU faults). We want to
+        /*
+         * 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 = arm_v7m_mmu_idx_for_secstate(env, true);
@@ -9443,7 +9488,8 @@ static void arm_log_exception(int idx)
 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 success,
+    /*
+     * Load a 16-bit portion of a v7M instruction, returning true on success,
      * or false on failure (in which case we will have pended the appropriate
      * exception).
      * We need to do the instruction fetch's MPU and SAU checks
@@ -9466,7 +9512,8 @@ static bool v7m_read_half_insn(ARMCPU *cpu, ARMMMUIdx mmu_idx,
 
     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
+        /*
+         * 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 |= R_V7M_SFSR_INVEP_MASK;
@@ -9496,7 +9543,8 @@ static bool v7m_read_half_insn(ARMCPU *cpu, ARMMMUIdx mmu_idx,
 
 static bool v7m_handle_execute_nsc(ARMCPU *cpu)
 {
-    /* Check whether this attempt to execute code in a Secure & NS-Callable
+    /*
+     * 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.
@@ -9505,7 +9553,8 @@ static bool v7m_handle_execute_nsc(ARMCPU *cpu)
     ARMMMUIdx mmu_idx;
     uint16_t insn;
 
-    /* We should never get here unless get_phys_addr_pmsav8() caused
+    /*
+     * We should never get here unless get_phys_addr_pmsav8() caused
      * an exception for NS executing in S&NSC memory.
      */
     assert(!env->v7m.secure);
@@ -9523,7 +9572,8 @@ static bool v7m_handle_execute_nsc(ARMCPU *cpu)
     }
 
     if (insn != 0xe97f) {
-        /* Not an SG instruction first half (we choose the IMPDEF
+        /*
+         * Not an SG instruction first half (we choose the IMPDEF
          * early-SG-check option).
          */
         goto gen_invep;
@@ -9534,13 +9584,15 @@ static bool v7m_handle_execute_nsc(ARMCPU *cpu)
     }
 
     if (insn != 0xe97f) {
-        /* Not an SG instruction second half (yes, both halves of the SG
+        /*
+         * 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.
+    /*
+     * 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" PRIx32
@@ -9569,8 +9621,10 @@ void arm_v7m_cpu_do_interrupt(CPUState *cs)
 
     arm_log_exception(cs->exception_index);
 
-    /* For exceptions we just mark as pending on the NVIC, and let that
-       handle it.  */
+    /*
+     * 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.secure);
@@ -9616,13 +9670,15 @@ void arm_v7m_cpu_do_interrupt(CPUState *cs)
         break;
     case EXCP_PREFETCH_ABORT:
     case EXCP_DATA_ABORT:
-        /* Note that for M profile we don't have a guest facing FSR, but
+        /*
+         * 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 address
+            /*
+             * Exception generated when we try to execute code at an address
              * 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
@@ -9635,7 +9691,8 @@ void arm_v7m_cpu_do_interrupt(CPUState *cs)
             }
             break;
         case M_FAKE_FSR_SFAULT:
-            /* Various flavours of SecureFault for attempts to execute or
+            /*
+             * Various flavours of SecureFault for attempts to execute or
              * access data in the wrong security state.
              */
             switch (cs->exception_index) {
@@ -9677,7 +9734,8 @@ void arm_v7m_cpu_do_interrupt(CPUState *cs)
             armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_BUS, false);
             break;
         default:
-            /* All other FSR values are either MPU faults or "can't happen
+            /*
+             * All other FSR values are either MPU faults or "can't happen
              * for M profile" cases.
              */
             switch (cs->exception_index) {
@@ -9743,7 +9801,8 @@ void arm_v7m_cpu_do_interrupt(CPUState *cs)
     if (arm_feature(env, ARM_FEATURE_V8)) {
         lr = R_V7M_EXCRET_RES1_MASK |
             R_V7M_EXCRET_DCRS_MASK;
-        /* The S bit indicates whether we should return to Secure
+        /*
+         * 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
@@ -12760,7 +12819,8 @@ uint32_t HELPER(v7m_mrs)(CPUARMState *env, uint32_t reg)
         return value;
     }
     case 0x94: /* CONTROL_NS */
-        /* We have to handle this here because unprivileged Secure code
+        /*
+         * We have to handle this here because unprivileged Secure code
          * can read the NS CONTROL register.
          */
         if (!env->v7m.secure) {
@@ -12813,7 +12873,8 @@ uint32_t HELPER(v7m_mrs)(CPUARMState *env, uint32_t reg)
             return env->v7m.faultmask[M_REG_NS];
         case 0x98: /* SP_NS */
         {
-            /* This gives the non-secure SP selected based on whether we're
+            /*
+             * This gives the non-secure SP selected based on whether we're
              * currently in handler mode or not, using the NS CONTROL.SPSEL.
              */
             bool spsel = env->v7m.control[M_REG_NS] & R_V7M_CONTROL_SPSEL_MASK;
@@ -12864,7 +12925,8 @@ uint32_t HELPER(v7m_mrs)(CPUARMState *env, uint32_t reg)
 
 void HELPER(v7m_msr)(CPUARMState *env, uint32_t maskreg, uint32_t val)
 {
-    /* We're passed bits [11..0] of the instruction; extract
+    /*
+     * 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.
@@ -12950,7 +13012,8 @@ void HELPER(v7m_msr)(CPUARMState *env, uint32_t maskreg, uint32_t val)
             return;
         case 0x98: /* SP_NS */
         {
-            /* This gives the non-secure SP selected based on whether we're
+            /*
+             * This gives the non-secure SP selected based on whether we're
              * currently in handler mode or not, using the NS CONTROL.SPSEL.
              */
             bool spsel = env->v7m.control[M_REG_NS] & R_V7M_CONTROL_SPSEL_MASK;
@@ -13111,7 +13174,8 @@ uint32_t HELPER(v7m_tt)(CPUARMState *env, uint32_t addr, uint32_t op)
     bool targetsec = env->v7m.secure;
     bool is_subpage;
 
-    /* Work out what the security state and privilege level we're
+    /*
+     * Work out what the security state and privilege level we're
      * interested in is...
      */
     if (alt) {
@@ -13128,12 +13192,14 @@ uint32_t HELPER(v7m_tt)(CPUARMState *env, uint32_t addr, uint32_t op)
     /* ...and then figure out which MMU index this is */
     mmu_idx = arm_v7m_mmu_idx_for_secstate_and_priv(env, targetsec, targetpriv);
 
-    /* We know that the MPU and SAU don't care about the access type
+    /*
+     * 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
+    /*
+     * MPU region info only available for privileged or if
      * inspecting the other MPU state.
      */
     if (arm_current_el(env) != 0 || alt) {
@@ -13238,7 +13304,8 @@ bool arm_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
 
 void HELPER(dc_zva)(CPUARMState *env, uint64_t vaddr_in)
 {
-    /* Implement DC ZVA, which zeroes a fixed-length block of memory.
+    /*
+     * Implement DC ZVA, which zeroes a fixed-length block of memory.
      * Note that we do not implement the (architecturally mandated)
      * alignment fault for attempts to use this on Device memory
      * (which matches the usual QEMU behaviour of not implementing either
@@ -13251,7 +13318,8 @@ void HELPER(dc_zva)(CPUARMState *env, uint64_t vaddr_in)
 
 #ifndef CONFIG_USER_ONLY
     {
-        /* Slightly awkwardly, QEMU's TARGET_PAGE_SIZE may be less than
+        /*
+         * Slightly awkwardly, QEMU's TARGET_PAGE_SIZE may be less than
          * the block size so we might have to do more than one TLB lookup.
          * We know that in fact for any v8 CPU the page size is at least 4K
          * and the block size must be 2K or less, but TARGET_PAGE_SIZE is only
@@ -13278,7 +13346,8 @@ void HELPER(dc_zva)(CPUARMState *env, uint64_t vaddr_in)
                 }
             }
             if (i == maxidx) {
-                /* If it's all in the TLB it's fair game for just writing to;
+                /*
+                 * If it's all in the TLB it's fair game for just writing to;
                  * we know we don't need to update dirty status, etc.
                  */
                 for (i = 0; i < maxidx - 1; i++) {
@@ -13287,7 +13356,8 @@ void HELPER(dc_zva)(CPUARMState *env, uint64_t vaddr_in)
                 memset(hostaddr[i], 0, blocklen - (i * TARGET_PAGE_SIZE));
                 return;
             }
-            /* OK, try a store and see if we can populate the tlb. This
+            /*
+             * OK, try a store and see if we can populate the tlb. This
              * might cause an exception if the memory isn't writable,
              * in which case we will longjmp out of here. We must for
              * this purpose use the actual register value passed to us
@@ -13303,7 +13373,8 @@ void HELPER(dc_zva)(CPUARMState *env, uint64_t vaddr_in)
             }
         }
 
-        /* Slow path (probably attempt to do this to an I/O device or
+        /*
+         * Slow path (probably attempt to do this to an I/O device or
          * similar, or clearing of a block of code we have translations
          * cached for). Just do a series of byte writes as the architecture
          * demands. It's not worth trying to use a cpu_physical_memory_map(),
diff --git a/target/arm/op_helper.c b/target/arm/op_helper.c
index 4db254876d..db4254a67b 100644
--- a/target/arm/op_helper.c
+++ b/target/arm/op_helper.c
@@ -970,7 +970,8 @@ static bool linked_bp_matches(ARMCPU *cpu, int lbn)
     int bt;
     uint32_t contextidr;
 
-    /* Links to unimplemented or non-context aware breakpoints are
+    /*
+     * 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<n>_EL1.LBN must indicate that breakpoint).
@@ -989,7 +990,8 @@ static bool linked_bp_matches(ARMCPU *cpu, int lbn)
 
     bt = extract64(bcr, 20, 4);
 
-    /* We match the whole register even if this is AArch32 using the
+    /*
+     * We match the whole register even if this is AArch32 using the
      * short descriptor format (in which case it holds both PROCID and ASID),
      * since we don't implement the optional v7 context ID masking.
      */
@@ -1006,7 +1008,8 @@ static bool linked_bp_matches(ARMCPU *cpu, int lbn)
     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
+        /*
+         * Links to Unlinked context breakpoints must generate no
          * events; we choose to do the same for reserved values too.
          */
         return false;
@@ -1020,7 +1023,8 @@ static bool bp_wp_matches(ARMCPU *cpu, int n, bool is_wp)
     CPUARMState *env = &cpu->env;
     uint64_t cr;
     int pac, hmc, ssc, wt, lbn;
-    /* Note that for watchpoints the check is against the CPU security
+    /*
+     * 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 = arm_is_secure(env);
@@ -1034,7 +1038,8 @@ static bool bp_wp_matches(ARMCPU *cpu, int n, bool is_wp)
         }
         cr = env->cp15.dbgwcr[n];
         if (wp->hitattrs.user) {
-            /* The LDRT/STRT/LDT/STT "unprivileged access" instructions should
+            /*
+             * The LDRT/STRT/LDT/STT "unprivileged access" instructions should
              * match watchpoints as if they were accesses done at EL0, even if
              * the CPU is at EL1 or higher.
              */
@@ -1048,7 +1053,8 @@ static bool bp_wp_matches(ARMCPU *cpu, int n, bool is_wp)
         }
         cr = env->cp15.dbgbcr[n];
     }
-    /* The WATCHPOINT_HIT flag guarantees us that the watchpoint is
+    /*
+     * 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
@@ -1116,7 +1122,8 @@ static bool check_watchpoints(ARMCPU *cpu)
     CPUARMState *env = &cpu->env;
     int n;
 
-    /* If watchpoints are disabled globally or we can't take debug
+    /*
+     * 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) == 0
@@ -1164,7 +1171,8 @@ void HELPER(check_breakpoints)(CPUARMState *env)
 
 bool arm_debug_check_watchpoint(CPUState *cs, CPUWatchpoint *wp)
 {
-    /* Called by core code when a CPU watchpoint fires; need to check if this
+    /*
+     * Called by core code when a CPU watchpoint fires; need to check if this
      * is also an architectural watchpoint match.
      */
     ARMCPU *cpu = ARM_CPU(cs);
@@ -1177,7 +1185,8 @@ vaddr arm_adjust_watchpoint_address(CPUState *cs, vaddr addr, int len)
     ARMCPU *cpu = ARM_CPU(cs);
     CPUARMState *env = &cpu->env;
 
-    /* In BE32 system mode, target memory is stored byteswapped (on a
+    /*
+     * 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.
-- 
2.20.1



^ permalink raw reply related	[flat|nested] 51+ messages in thread

* [Qemu-devel] [PATCH v2 07/23] target/arm: Declare some function publicly
  2019-06-15 15:43 [Qemu-devel] [PATCH v2 00/23] Support disabling TCG on ARM Philippe Mathieu-Daudé
                   ` (5 preceding siblings ...)
  2019-06-15 15:43 ` [Qemu-devel] [PATCH v2 06/23] target/arm: Fix multiline comment syntax Philippe Mathieu-Daudé
@ 2019-06-15 15:43 ` Philippe Mathieu-Daudé
  2019-06-17 14:07   ` [Qemu-devel] [Qemu-arm] " Alex Bennée
  2019-06-15 15:43 ` [Qemu-devel] [PATCH v2 08/23] target/arm: Move all v7m insn helpers into their own file Philippe Mathieu-Daudé
                   ` (15 subsequent siblings)
  22 siblings, 1 reply; 51+ messages in thread
From: Philippe Mathieu-Daudé @ 2019-06-15 15:43 UTC (permalink / raw)
  To: qemu-devel; +Cc: Peter Maydell, qemu-arm, Philippe Mathieu-Daudé

In few commits we will split the v7-M functions from this file.
Some function will be called out of helper.c. Declare them
in the "internals.h" header.

Signed-off-by: Philippe Mathieu-Daudé <philmd@redhat.com>
---
 target/arm/helper.c    | 69 +++++++++++++-----------------------------
 target/arm/internals.h | 45 +++++++++++++++++++++++++++
 2 files changed, 66 insertions(+), 48 deletions(-)

diff --git a/target/arm/helper.c b/target/arm/helper.c
index 9a3766b759..a1e74cc471 100644
--- a/target/arm/helper.c
+++ b/target/arm/helper.c
@@ -35,17 +35,6 @@
 #define ARM_CPU_FREQ 1000000000 /* FIXME: 1 GHz, should be configurable */
 
 #ifndef CONFIG_USER_ONLY
-/* Cacheability and shareability attributes for a memory access */
-typedef struct ARMCacheAttrs {
-    unsigned int attrs:8; /* as in the MAIR register encoding */
-    unsigned int shareability:2; /* as in the SH field of the VMSAv8-64 PTEs */
-} ARMCacheAttrs;
-
-static bool get_phys_addr(CPUARMState *env, target_ulong address,
-                          MMUAccessType access_type, ARMMMUIdx mmu_idx,
-                          hwaddr *phys_ptr, MemTxAttrs *attrs, int *prot,
-                          target_ulong *page_size,
-                          ARMMMUFaultInfo *fi, ARMCacheAttrs *cacheattrs);
 
 static bool get_phys_addr_lpae(CPUARMState *env, target_ulong address,
                                MMUAccessType access_type, ARMMMUIdx mmu_idx,
@@ -53,24 +42,8 @@ static bool get_phys_addr_lpae(CPUARMState *env, target_ulong address,
                                target_ulong *page_size_ptr,
                                ARMMMUFaultInfo *fi, ARMCacheAttrs *cacheattrs);
 
-/* Security attributes for an address, as returned by v8m_security_lookup. */
-typedef struct V8M_SAttributes {
-    bool subpage; /* true if these attrs don't cover the whole TARGET_PAGE */
-    bool ns;
-    bool nsc;
-    uint8_t sregion;
-    bool srvalid;
-    uint8_t iregion;
-    bool irvalid;
-} V8M_SAttributes;
-
-static void v8m_security_lookup(CPUARMState *env, uint32_t address,
-                                MMUAccessType access_type, ARMMMUIdx mmu_idx,
-                                V8M_SAttributes *sattrs);
 #endif
 
-static void switch_mode(CPUARMState *env, int mode);
-
 static int vfp_gdb_get_reg(CPUARMState *env, uint8_t *buf, int reg)
 {
     int nregs;
@@ -7552,7 +7525,7 @@ uint32_t HELPER(v7m_tt)(CPUARMState *env, uint32_t addr, uint32_t op)
     return 0;
 }
 
-static void switch_mode(CPUARMState *env, int mode)
+void switch_mode(CPUARMState *env, int mode)
 {
     ARMCPU *cpu = env_archcpu(env);
 
@@ -7574,7 +7547,7 @@ void aarch64_sync_64_to_32(CPUARMState *env)
 
 #else
 
-static void switch_mode(CPUARMState *env, int mode)
+void switch_mode(CPUARMState *env, int mode)
 {
     int old_mode;
     int i;
@@ -7988,9 +7961,9 @@ void HELPER(v7m_preserve_fp_state)(CPUARMState *env)
  * 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)
+void write_v7m_control_spsel_for_secstate(CPUARMState *env,
+                                          bool new_spsel,
+                                          bool secstate)
 {
     bool old_is_psp = v7m_using_psp(env);
 
@@ -8015,7 +7988,7 @@ static void write_v7m_control_spsel_for_secstate(CPUARMState *env,
  * 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)
+void write_v7m_control_spsel(CPUARMState *env, bool new_spsel)
 {
     write_v7m_control_spsel_for_secstate(env, new_spsel, env->v7m.secure);
 }
@@ -8041,7 +8014,7 @@ void write_v7m_exception(CPUARMState *env, uint32_t new_exc)
 }
 
 /* Switch M profile security state between NS and S */
-static void switch_v7m_security_state(CPUARMState *env, bool new_secstate)
+void switch_v7m_security_state(CPUARMState *env, bool new_secstate)
 {
     uint32_t new_ss_msp, new_ss_psp;
 
@@ -9447,7 +9420,7 @@ static bool do_v7m_function_return(ARMCPU *cpu)
     return true;
 }
 
-static void arm_log_exception(int idx)
+void arm_log_exception(int idx)
 {
     if (qemu_loglevel_mask(CPU_LOG_INT)) {
         const char *exc = NULL;
@@ -12122,9 +12095,9 @@ static bool v8m_is_sau_exempt(CPUARMState *env,
         (address >= 0xe00ff000 && address <= 0xe00fffff);
 }
 
-static void v8m_security_lookup(CPUARMState *env, uint32_t address,
-                                MMUAccessType access_type, ARMMMUIdx mmu_idx,
-                                V8M_SAttributes *sattrs)
+void v8m_security_lookup(CPUARMState *env, uint32_t address,
+                         MMUAccessType access_type, ARMMMUIdx mmu_idx,
+                         V8M_SAttributes *sattrs)
 {
     /* Look up the security attributes for this address. Compare the
      * pseudocode SecurityCheck() function.
@@ -12229,11 +12202,11 @@ static void v8m_security_lookup(CPUARMState *env, uint32_t address,
     }
 }
 
-static bool pmsav8_mpu_lookup(CPUARMState *env, uint32_t address,
-                              MMUAccessType access_type, ARMMMUIdx mmu_idx,
-                              hwaddr *phys_ptr, MemTxAttrs *txattrs,
-                              int *prot, bool *is_subpage,
-                              ARMMMUFaultInfo *fi, uint32_t *mregion)
+bool pmsav8_mpu_lookup(CPUARMState *env, uint32_t address,
+                       MMUAccessType access_type, ARMMMUIdx mmu_idx,
+                       hwaddr *phys_ptr, MemTxAttrs *txattrs,
+                       int *prot, bool *is_subpage,
+                       ARMMMUFaultInfo *fi, uint32_t *mregion)
 {
     /* Perform a PMSAv8 MPU lookup (without also doing the SAU check
      * that a full phys-to-virt translation does).
@@ -12633,11 +12606,11 @@ static ARMCacheAttrs combine_cacheattrs(ARMCacheAttrs s1, ARMCacheAttrs s2)
  * @fi: set to fault info if the translation fails
  * @cacheattrs: (if non-NULL) set to the cacheability/shareability attributes
  */
-static bool get_phys_addr(CPUARMState *env, target_ulong address,
-                          MMUAccessType access_type, ARMMMUIdx mmu_idx,
-                          hwaddr *phys_ptr, MemTxAttrs *attrs, int *prot,
-                          target_ulong *page_size,
-                          ARMMMUFaultInfo *fi, ARMCacheAttrs *cacheattrs)
+bool get_phys_addr(CPUARMState *env, target_ulong address,
+                   MMUAccessType access_type, ARMMMUIdx mmu_idx,
+                   hwaddr *phys_ptr, MemTxAttrs *attrs, int *prot,
+                   target_ulong *page_size,
+                   ARMMMUFaultInfo *fi, ARMCacheAttrs *cacheattrs)
 {
     if (mmu_idx == ARMMMUIdx_S12NSE0 || mmu_idx == ARMMMUIdx_S12NSE1) {
         /* Call ourselves recursively to do the stage 1 and then stage 2
diff --git a/target/arm/internals.h b/target/arm/internals.h
index 5a02f458f3..04711b317a 100644
--- a/target/arm/internals.h
+++ b/target/arm/internals.h
@@ -985,4 +985,49 @@ static inline int exception_target_el(CPUARMState *env)
     return target_el;
 }
 
+void arm_log_exception(int idx);
+
+/* Cacheability and shareability attributes for a memory access */
+typedef struct ARMCacheAttrs {
+    unsigned int attrs:8; /* as in the MAIR register encoding */
+    unsigned int shareability:2; /* as in the SH field of the VMSAv8-64 PTEs */
+} ARMCacheAttrs;
+
+bool get_phys_addr(CPUARMState *env, target_ulong address,
+                   MMUAccessType access_type, ARMMMUIdx mmu_idx,
+                   hwaddr *phys_ptr, MemTxAttrs *attrs, int *prot,
+                   target_ulong *page_size,
+                   ARMMMUFaultInfo *fi, ARMCacheAttrs *cacheattrs);
+
+/* Security attributes for an address, as returned by v8m_security_lookup. */
+typedef struct V8M_SAttributes {
+    bool subpage; /* true if these attrs don't cover the whole TARGET_PAGE */
+    bool ns;
+    bool nsc;
+    uint8_t sregion;
+    bool srvalid;
+    uint8_t iregion;
+    bool irvalid;
+} V8M_SAttributes;
+
+void v8m_security_lookup(CPUARMState *env, uint32_t address,
+                         MMUAccessType access_type, ARMMMUIdx mmu_idx,
+                         V8M_SAttributes *sattrs);
+
+void switch_mode(CPUARMState *, int);
+
+bool pmsav8_mpu_lookup(CPUARMState *env, uint32_t address,
+                       MMUAccessType access_type, ARMMMUIdx mmu_idx,
+                       hwaddr *phys_ptr, MemTxAttrs *txattrs,
+                       int *prot, bool *is_subpage,
+                       ARMMMUFaultInfo *fi, uint32_t *mregion);
+
+void write_v7m_control_spsel_for_secstate(CPUARMState *env,
+                                          bool new_spsel,
+                                          bool secstate);
+
+void write_v7m_control_spsel(CPUARMState *env, bool new_spsel);
+
+void switch_v7m_security_state(CPUARMState *env, bool new_secstate);
+
 #endif
-- 
2.20.1



^ permalink raw reply related	[flat|nested] 51+ messages in thread

* [Qemu-devel] [PATCH v2 08/23] target/arm: Move all v7m insn helpers into their own file
  2019-06-15 15:43 [Qemu-devel] [PATCH v2 00/23] Support disabling TCG on ARM Philippe Mathieu-Daudé
                   ` (6 preceding siblings ...)
  2019-06-15 15:43 ` [Qemu-devel] [PATCH v2 07/23] target/arm: Declare some function publicly Philippe Mathieu-Daudé
@ 2019-06-15 15:43 ` Philippe Mathieu-Daudé
  2019-06-17 11:42   ` Alex Bennée
  2019-06-15 15:43 ` [Qemu-devel] [PATCH v2 09/23] target/arm: Move code around Philippe Mathieu-Daudé
                   ` (14 subsequent siblings)
  22 siblings, 1 reply; 51+ messages in thread
From: Philippe Mathieu-Daudé @ 2019-06-15 15:43 UTC (permalink / raw)
  To: qemu-devel
  Cc: Peter Maydell, qemu-arm, Philippe Mathieu-Daudé, Samuel Ortiz

From: Samuel Ortiz <sameo@linux.intel.com>

In preparation for supporting TCG disablement on ARM, we move most
of TCG related v7m helpers and APIs into their own file.

Signed-off-by: Samuel Ortiz <sameo@linux.intel.com>
[PMD: Patch rewritten]
Signed-off-by: Philippe Mathieu-Daudé <philmd@redhat.com>
---
Is there a way to not use $CONFIG_USER_ONLY?

 target/arm/Makefile.objs |   1 +
 target/arm/helper.c      | 633 -------------------------------------
 target/arm/v7m_helper.c  | 654 +++++++++++++++++++++++++++++++++++++++
 3 files changed, 655 insertions(+), 633 deletions(-)
 create mode 100644 target/arm/v7m_helper.c

diff --git a/target/arm/Makefile.objs b/target/arm/Makefile.objs
index 72b42f825f..5f3f965cc6 100644
--- a/target/arm/Makefile.objs
+++ b/target/arm/Makefile.objs
@@ -35,6 +35,7 @@ obj-y += translate.o op_helper.o
 obj-y += crypto_helper.o
 obj-y += iwmmxt_helper.o vec_helper.o
 obj-y += neon_helper.o vfp_helper.o
+obj-$(call lor,$(CONFIG_USER_ONLY),$(CONFIG_ARM_V7M)) += v7m_helper.o
 
 obj-$(TARGET_AARCH64) += translate-a64.o helper-a64.o
 obj-$(TARGET_AARCH64) += translate-sve.o sve_helper.o
diff --git a/target/arm/helper.c b/target/arm/helper.c
index a1e74cc471..a829086c6d 100644
--- a/target/arm/helper.c
+++ b/target/arm/helper.c
@@ -20,7 +20,6 @@
 #include "qemu/crc32c.h"
 #include "qemu/qemu-print.h"
 #include "exec/exec-all.h"
-#include "exec/cpu_ldst.h"
 #include "arm_ldst.h"
 #include <zlib.h> /* For crc32 */
 #include "hw/semihosting/semihost.h"
@@ -7456,75 +7455,6 @@ uint32_t HELPER(rbit)(uint32_t x)
 
 #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 = env_archcpu(env);
-
-    cpu_abort(CPU(cpu), "v7m_msr %d\n", reg);
-}
-
-uint32_t HELPER(v7m_mrs)(CPUARMState *env, uint32_t reg)
-{
-    ARMCPU *cpu = 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;
-}
-
 void switch_mode(CPUARMState *env, int mode)
 {
     ARMCPU *cpu = env_archcpu(env);
@@ -8048,109 +7978,6 @@ void switch_v7m_security_state(CPUARMState *env, bool new_secstate)
     }
 }
 
-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 = FNC_RETURN_MIN_MAGIC;
-    } else {
-        /* EXC_RETURN magic only */
-        min_magic = EXC_RETURN_MIN_MAGIC;
-    }
-
-    if (dest >= 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 complete"
-         * event (compare gen_bx_excret_final_code()).
-         */
-        env->regs[15] = dest & ~1;
-        env->thumb = 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] &= ~R_V7M_CONTROL_SFPA_MASK;
-    }
-    switch_v7m_security_state(env, dest & 1);
-    env->thumb = 1;
-    env->regs[15] = 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 = env->regs[15] | 1;
-    uint32_t sp = 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] = nextinst;
-        env->thumb = 1;
-        env->regs[15] = 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 = env->v7m.exception;
-    if (env->v7m.control[M_REG_S] & R_V7M_CONTROL_SFPA_MASK) {
-        saved_psr |= 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] = sp;
-    env->regs[14] = 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] &= ~R_V7M_CONTROL_SFPA_MASK;
-    switch_v7m_security_state(env, 0);
-    env->thumb = 1;
-    env->regs[15] = dest;
-}
-
 static uint32_t *get_v7m_sp_ptr(CPUARMState *env, bool secure, bool threadmode,
                                 bool spsel)
 {
@@ -12760,466 +12587,6 @@ hwaddr arm_cpu_get_phys_page_attrs_debug(CPUState *cs, vaddr addr,
     return phys_addr;
 }
 
-uint32_t HELPER(v7m_mrs)(CPUARMState *env, uint32_t reg)
-{
-    uint32_t mask;
-    unsigned el = arm_current_el(env);
-
-    /* First handle registers which unprivileged can read */
-
-    switch (reg) {
-    case 0 ... 7: /* xPSR sub-fields */
-        mask = 0;
-        if ((reg & 1) && el) {
-            mask |= XPSR_EXCP; /* IPSR (unpriv. reads as zero) */
-        }
-        if (!(reg & 4)) {
-            mask |= XPSR_NZCV | XPSR_Q; /* APSR */
-            if (arm_feature(env, ARM_FEATURE_THUMB_DSP)) {
-                mask |= XPSR_GE;
-            }
-        }
-        /* EPSR reads as zero */
-        return xpsr_read(env) & mask;
-        break;
-    case 20: /* CONTROL */
-    {
-        uint32_t value = 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 |= 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 == 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.SPSEL.
-             */
-            bool spsel = env->v7m.control[M_REG_NS] & R_V7M_CONTROL_SPSEL_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 = extract32(maskreg, 8, 4);
-    uint32_t reg = extract32(maskreg, 0, 8);
-    int cur_el = arm_current_el(env);
-
-    if (cur_el == 0 && reg > 7 && reg != 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 = val;
-            return;
-        case 0x89: /* PSP_NS */
-            if (!env->v7m.secure) {
-                return;
-            }
-            env->v7m.other_ss_psp = val;
-            return;
-        case 0x8a: /* MSPLIM_NS */
-            if (!env->v7m.secure) {
-                return;
-            }
-            env->v7m.msplim[M_REG_NS] = val & ~7;
-            return;
-        case 0x8b: /* PSPLIM_NS */
-            if (!env->v7m.secure) {
-                return;
-            }
-            env->v7m.psplim[M_REG_NS] = val & ~7;
-            return;
-        case 0x90: /* PRIMASK_NS */
-            if (!env->v7m.secure) {
-                return;
-            }
-            env->v7m.primask[M_REG_NS] = 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] = 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] = 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] &= ~R_V7M_CONTROL_NPRIV_MASK;
-                env->v7m.control[M_REG_NS] |= val & R_V7M_CONTROL_NPRIV_MASK;
-            }
-            /*
-             * SFPA is RAZ/WI from NS. FPCA is RO if NSACR.CP10 == 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] &= ~R_V7M_CONTROL_FPCA_MASK;
-                env->v7m.control[M_REG_S] |= val & R_V7M_CONTROL_FPCA_MASK;
-            }
-            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.SPSEL.
-             */
-            bool spsel = env->v7m.control[M_REG_NS] & R_V7M_CONTROL_SPSEL_MASK;
-            bool is_psp = !arm_v7m_is_handler_mode(env) && spsel;
-            uint32_t limit;
-
-            if (!env->v7m.secure) {
-                return;
-            }
-
-            limit = is_psp ? env->v7m.psplim[false] : env->v7m.msplim[false];
-
-            if (val < limit) {
-                CPUState *cs = env_cpu(env);
-
-                cpu_restore_state(cs, GETPC(), true);
-                raise_exception(env, EXCP_STKOF, 0, 1);
-            }
-
-            if (is_psp) {
-                env->v7m.other_ss_psp = val;
-            } else {
-                env->v7m.other_ss_msp = val;
-            }
-            return;
-        }
-        default:
-            break;
-        }
-    }
-
-    switch (reg) {
-    case 0 ... 7: /* xPSR sub-fields */
-        /* only APSR is actually writable */
-        if (!(reg & 4)) {
-            uint32_t apsrmask = 0;
-
-            if (mask & 8) {
-                apsrmask |= XPSR_NZCV | XPSR_Q;
-            }
-            if ((mask & 4) && arm_feature(env, ARM_FEATURE_THUMB_DSP)) {
-                apsrmask |= XPSR_GE;
-            }
-            xpsr_write(env, val, apsrmask);
-        }
-        break;
-    case 8: /* MSP */
-        if (v7m_using_psp(env)) {
-            env->v7m.other_sp = val;
-        } else {
-            env->regs[13] = val;
-        }
-        break;
-    case 9: /* PSP */
-        if (v7m_using_psp(env)) {
-            env->regs[13] = val;
-        } else {
-            env->v7m.other_sp = val;
-        }
-        break;
-    case 10: /* MSPLIM */
-        if (!arm_feature(env, ARM_FEATURE_V8)) {
-            goto bad_reg;
-        }
-        env->v7m.msplim[env->v7m.secure] = val & ~7;
-        break;
-    case 11: /* PSPLIM */
-        if (!arm_feature(env, ARM_FEATURE_V8)) {
-            goto bad_reg;
-        }
-        env->v7m.psplim[env->v7m.secure] = val & ~7;
-        break;
-    case 16: /* PRIMASK */
-        env->v7m.primask[env->v7m.secure] = val & 1;
-        break;
-    case 17: /* BASEPRI */
-        if (!arm_feature(env, ARM_FEATURE_M_MAIN)) {
-            goto bad_reg;
-        }
-        env->v7m.basepri[env->v7m.secure] = val & 0xff;
-        break;
-    case 18: /* BASEPRI_MAX */
-        if (!arm_feature(env, ARM_FEATURE_M_MAIN)) {
-            goto bad_reg;
-        }
-        val &= 0xff;
-        if (val != 0 && (val < env->v7m.basepri[env->v7m.secure]
-                         || env->v7m.basepri[env->v7m.secure] == 0)) {
-            env->v7m.basepri[env->v7m.secure] = val;
-        }
-        break;
-    case 19: /* FAULTMASK */
-        if (!arm_feature(env, ARM_FEATURE_M_MAIN)) {
-            goto bad_reg;
-        }
-        env->v7m.faultmask[env->v7m.secure] = 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) != 0);
-        }
-        if (cur_el > 0 && arm_feature(env, ARM_FEATURE_M_MAIN)) {
-            env->v7m.control[env->v7m.secure] &= ~R_V7M_CONTROL_NPRIV_MASK;
-            env->v7m.control[env->v7m.secure] |= val & R_V7M_CONTROL_NPRIV_MASK;
-        }
-        if (arm_feature(env, ARM_FEATURE_VFP)) {
-            /*
-             * SFPA is RAZ/WI from NS or if no FPU.
-             * FPCA is RO if NSACR.CP10 == 0, RES0 if the FPU is not present.
-             * Both are stored in the S bank.
-             */
-            if (env->v7m.secure) {
-                env->v7m.control[M_REG_S] &= ~R_V7M_CONTROL_SFPA_MASK;
-                env->v7m.control[M_REG_S] |= val & R_V7M_CONTROL_SFPA_MASK;
-            }
-            if (cur_el > 0 &&
-                (env->v7m.secure || !arm_feature(env, ARM_FEATURE_M_SECURITY) ||
-                 extract32(env->v7m.nsacr, 10, 1))) {
-                env->v7m.control[M_REG_S] &= ~R_V7M_CONTROL_FPCA_MASK;
-                env->v7m.control[M_REG_S] |= val & R_V7M_CONTROL_FPCA_MASK;
-            }
-        }
-        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 = op & 1;
-    bool alt = op & 2;
-    V8M_SAttributes sattrs = {};
-    uint32_t tt_resp;
-    bool r, rw, nsr, nsrw, mrvalid;
-    int prot;
-    ARMMMUFaultInfo fi = {};
-    MemTxAttrs attrs = {};
-    hwaddr phys_addr;
-    ARMMMUIdx mmu_idx;
-    uint32_t mregion;
-    bool targetpriv;
-    bool targetsec = env->v7m.secure;
-    bool is_subpage;
-
-    /*
-     * Work out what the security state and privilege level we're
-     * interested in is...
-     */
-    if (alt) {
-        targetsec = !targetsec;
-    }
-
-    if (forceunpriv) {
-        targetpriv = false;
-    } else {
-        targetpriv = 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 = arm_v7m_mmu_idx_for_secstate_and_priv(env, targetsec, targetpriv);
-
-    /*
-     * 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) != 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 == -1) {
-            mrvalid = false;
-            mregion = 0;
-        } else {
-            mrvalid = true;
-        }
-        r = prot & PAGE_READ;
-        rw = prot & PAGE_WRITE;
-    } else {
-        r = false;
-        rw = false;
-        mrvalid = false;
-        mregion = 0;
-    }
-
-    if (env->v7m.secure) {
-        v8m_security_lookup(env, addr, MMU_DATA_LOAD, mmu_idx, &sattrs);
-        nsr = sattrs.ns && r;
-        nsrw = sattrs.ns && rw;
-    } else {
-        sattrs.ns = true;
-        nsr = false;
-        nsrw = false;
-    }
-
-    tt_resp = (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
 
 bool arm_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
diff --git a/target/arm/v7m_helper.c b/target/arm/v7m_helper.c
new file mode 100644
index 0000000000..321154966e
--- /dev/null
+++ b/target/arm/v7m_helper.c
@@ -0,0 +1,654 @@
+/*
+ * ARM v7-M 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 "sysemu/sysemu.h"
+#include "cpu.h"
+#include "internals.h"
+#include "exec/helper-proto.h"
+#include "exec/exec-all.h"
+#include "arm_ldst.h"
+#include "hw/semihosting/semihost.h"
+#include "fpu/softfloat.h"
+
+#if defined(CONFIG_USER_ONLY)
+
+/* These should probably raise undefined insn exceptions.  */
+void HELPER(v7m_msr)(CPUARMState *env, uint32_t reg, uint32_t val)
+{
+    ARMCPU *cpu = env_archcpu(env);
+
+    cpu_abort(CPU(cpu), "v7m_msr %d\n", reg);
+}
+
+uint32_t HELPER(v7m_mrs)(CPUARMState *env, uint32_t reg)
+{
+    ARMCPU *cpu = 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
+
+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 = FNC_RETURN_MIN_MAGIC;
+    } else {
+        /* EXC_RETURN magic only */
+        min_magic = EXC_RETURN_MIN_MAGIC;
+    }
+
+    if (dest >= 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 complete"
+         * event (compare gen_bx_excret_final_code()).
+         */
+        env->regs[15] = dest & ~1;
+        env->thumb = 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] &= ~R_V7M_CONTROL_SFPA_MASK;
+    }
+    switch_v7m_security_state(env, dest & 1);
+    env->thumb = 1;
+    env->regs[15] = 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 = env->regs[15] | 1;
+    uint32_t sp = 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] = nextinst;
+        env->thumb = 1;
+        env->regs[15] = 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 = env->v7m.exception;
+    if (env->v7m.control[M_REG_S] & R_V7M_CONTROL_SFPA_MASK) {
+        saved_psr |= 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] = sp;
+    env->regs[14] = 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] &= ~R_V7M_CONTROL_SFPA_MASK;
+    switch_v7m_security_state(env, 0);
+    env->thumb = 1;
+    env->regs[15] = dest;
+}
+
+uint32_t HELPER(v7m_mrs)(CPUARMState *env, uint32_t reg)
+{
+    uint32_t mask;
+    unsigned el = arm_current_el(env);
+
+    /* First handle registers which unprivileged can read */
+
+    switch (reg) {
+    case 0 ... 7: /* xPSR sub-fields */
+        mask = 0;
+        if ((reg & 1) && el) {
+            mask |= XPSR_EXCP; /* IPSR (unpriv. reads as zero) */
+        }
+        if (!(reg & 4)) {
+            mask |= XPSR_NZCV | XPSR_Q; /* APSR */
+            if (arm_feature(env, ARM_FEATURE_THUMB_DSP)) {
+                mask |= XPSR_GE;
+            }
+        }
+        /* EPSR reads as zero */
+        return xpsr_read(env) & mask;
+        break;
+    case 20: /* CONTROL */
+    {
+        uint32_t value = 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 |= 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 == 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.SPSEL.
+             */
+            bool spsel = env->v7m.control[M_REG_NS] & R_V7M_CONTROL_SPSEL_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 = extract32(maskreg, 8, 4);
+    uint32_t reg = extract32(maskreg, 0, 8);
+    int cur_el = arm_current_el(env);
+
+    if (cur_el == 0 && reg > 7 && reg != 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 = val;
+            return;
+        case 0x89: /* PSP_NS */
+            if (!env->v7m.secure) {
+                return;
+            }
+            env->v7m.other_ss_psp = val;
+            return;
+        case 0x8a: /* MSPLIM_NS */
+            if (!env->v7m.secure) {
+                return;
+            }
+            env->v7m.msplim[M_REG_NS] = val & ~7;
+            return;
+        case 0x8b: /* PSPLIM_NS */
+            if (!env->v7m.secure) {
+                return;
+            }
+            env->v7m.psplim[M_REG_NS] = val & ~7;
+            return;
+        case 0x90: /* PRIMASK_NS */
+            if (!env->v7m.secure) {
+                return;
+            }
+            env->v7m.primask[M_REG_NS] = 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] = 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] = 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] &= ~R_V7M_CONTROL_NPRIV_MASK;
+                env->v7m.control[M_REG_NS] |= val & R_V7M_CONTROL_NPRIV_MASK;
+            }
+            /*
+             * SFPA is RAZ/WI from NS. FPCA is RO if NSACR.CP10 == 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] &= ~R_V7M_CONTROL_FPCA_MASK;
+                env->v7m.control[M_REG_S] |= val & R_V7M_CONTROL_FPCA_MASK;
+            }
+            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.SPSEL.
+             */
+            bool spsel = env->v7m.control[M_REG_NS] & R_V7M_CONTROL_SPSEL_MASK;
+            bool is_psp = !arm_v7m_is_handler_mode(env) && spsel;
+            uint32_t limit;
+
+            if (!env->v7m.secure) {
+                return;
+            }
+
+            limit = is_psp ? env->v7m.psplim[false] : env->v7m.msplim[false];
+
+            if (val < limit) {
+                CPUState *cs = env_cpu(env);
+
+                cpu_restore_state(cs, GETPC(), true);
+                raise_exception(env, EXCP_STKOF, 0, 1);
+            }
+
+            if (is_psp) {
+                env->v7m.other_ss_psp = val;
+            } else {
+                env->v7m.other_ss_msp = val;
+            }
+            return;
+        }
+        default:
+            break;
+        }
+    }
+
+    switch (reg) {
+    case 0 ... 7: /* xPSR sub-fields */
+        /* only APSR is actually writable */
+        if (!(reg & 4)) {
+            uint32_t apsrmask = 0;
+
+            if (mask & 8) {
+                apsrmask |= XPSR_NZCV | XPSR_Q;
+            }
+            if ((mask & 4) && arm_feature(env, ARM_FEATURE_THUMB_DSP)) {
+                apsrmask |= XPSR_GE;
+            }
+            xpsr_write(env, val, apsrmask);
+        }
+        break;
+    case 8: /* MSP */
+        if (v7m_using_psp(env)) {
+            env->v7m.other_sp = val;
+        } else {
+            env->regs[13] = val;
+        }
+        break;
+    case 9: /* PSP */
+        if (v7m_using_psp(env)) {
+            env->regs[13] = val;
+        } else {
+            env->v7m.other_sp = val;
+        }
+        break;
+    case 10: /* MSPLIM */
+        if (!arm_feature(env, ARM_FEATURE_V8)) {
+            goto bad_reg;
+        }
+        env->v7m.msplim[env->v7m.secure] = val & ~7;
+        break;
+    case 11: /* PSPLIM */
+        if (!arm_feature(env, ARM_FEATURE_V8)) {
+            goto bad_reg;
+        }
+        env->v7m.psplim[env->v7m.secure] = val & ~7;
+        break;
+    case 16: /* PRIMASK */
+        env->v7m.primask[env->v7m.secure] = val & 1;
+        break;
+    case 17: /* BASEPRI */
+        if (!arm_feature(env, ARM_FEATURE_M_MAIN)) {
+            goto bad_reg;
+        }
+        env->v7m.basepri[env->v7m.secure] = val & 0xff;
+        break;
+    case 18: /* BASEPRI_MAX */
+        if (!arm_feature(env, ARM_FEATURE_M_MAIN)) {
+            goto bad_reg;
+        }
+        val &= 0xff;
+        if (val != 0 && (val < env->v7m.basepri[env->v7m.secure]
+                         || env->v7m.basepri[env->v7m.secure] == 0)) {
+            env->v7m.basepri[env->v7m.secure] = val;
+        }
+        break;
+    case 19: /* FAULTMASK */
+        if (!arm_feature(env, ARM_FEATURE_M_MAIN)) {
+            goto bad_reg;
+        }
+        env->v7m.faultmask[env->v7m.secure] = 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) != 0);
+        }
+        if (cur_el > 0 && arm_feature(env, ARM_FEATURE_M_MAIN)) {
+            env->v7m.control[env->v7m.secure] &= ~R_V7M_CONTROL_NPRIV_MASK;
+            env->v7m.control[env->v7m.secure] |= val & R_V7M_CONTROL_NPRIV_MASK;
+        }
+        if (arm_feature(env, ARM_FEATURE_VFP)) {
+            /*
+             * SFPA is RAZ/WI from NS or if no FPU.
+             * FPCA is RO if NSACR.CP10 == 0, RES0 if the FPU is not present.
+             * Both are stored in the S bank.
+             */
+            if (env->v7m.secure) {
+                env->v7m.control[M_REG_S] &= ~R_V7M_CONTROL_SFPA_MASK;
+                env->v7m.control[M_REG_S] |= val & R_V7M_CONTROL_SFPA_MASK;
+            }
+            if (cur_el > 0 &&
+                (env->v7m.secure || !arm_feature(env, ARM_FEATURE_M_SECURITY) ||
+                 extract32(env->v7m.nsacr, 10, 1))) {
+                env->v7m.control[M_REG_S] &= ~R_V7M_CONTROL_FPCA_MASK;
+                env->v7m.control[M_REG_S] |= val & R_V7M_CONTROL_FPCA_MASK;
+            }
+        }
+        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 = op & 1;
+    bool alt = op & 2;
+    V8M_SAttributes sattrs = {};
+    uint32_t tt_resp;
+    bool r, rw, nsr, nsrw, mrvalid;
+    int prot;
+    ARMMMUFaultInfo fi = {};
+    MemTxAttrs attrs = {};
+    hwaddr phys_addr;
+    ARMMMUIdx mmu_idx;
+    uint32_t mregion;
+    bool targetpriv;
+    bool targetsec = env->v7m.secure;
+    bool is_subpage;
+
+    /*
+     * Work out what the security state and privilege level we're
+     * interested in is...
+     */
+    if (alt) {
+        targetsec = !targetsec;
+    }
+
+    if (forceunpriv) {
+        targetpriv = false;
+    } else {
+        targetpriv = 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 = arm_v7m_mmu_idx_for_secstate_and_priv(env, targetsec, targetpriv);
+
+    /*
+     * 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) != 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 == -1) {
+            mrvalid = false;
+            mregion = 0;
+        } else {
+            mrvalid = true;
+        }
+        r = prot & PAGE_READ;
+        rw = prot & PAGE_WRITE;
+    } else {
+        r = false;
+        rw = false;
+        mrvalid = false;
+        mregion = 0;
+    }
+
+    if (env->v7m.secure) {
+        v8m_security_lookup(env, addr, MMU_DATA_LOAD, mmu_idx, &sattrs);
+        nsr = sattrs.ns && r;
+        nsrw = sattrs.ns && rw;
+    } else {
+        sattrs.ns = true;
+        nsr = false;
+        nsrw = false;
+    }
+
+    tt_resp = (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 */
-- 
2.20.1



^ permalink raw reply related	[flat|nested] 51+ messages in thread

* [Qemu-devel] [PATCH v2 09/23] target/arm: Move code around
  2019-06-15 15:43 [Qemu-devel] [PATCH v2 00/23] Support disabling TCG on ARM Philippe Mathieu-Daudé
                   ` (7 preceding siblings ...)
  2019-06-15 15:43 ` [Qemu-devel] [PATCH v2 08/23] target/arm: Move all v7m insn helpers into their own file Philippe Mathieu-Daudé
@ 2019-06-15 15:43 ` Philippe Mathieu-Daudé
  2019-06-17 14:07   ` [Qemu-devel] [Qemu-arm] " Alex Bennée
  2019-06-15 15:43 ` [Qemu-devel] [PATCH v2 10/23] target/arm: Move the v7-M Security State helpers to v7m_helper Philippe Mathieu-Daudé
                   ` (13 subsequent siblings)
  22 siblings, 1 reply; 51+ messages in thread
From: Philippe Mathieu-Daudé @ 2019-06-15 15:43 UTC (permalink / raw)
  To: qemu-devel; +Cc: Peter Maydell, qemu-arm, Philippe Mathieu-Daudé

To ease the review of the next commit, move the
write_v7m_exception() function around.

Signed-off-by: Philippe Mathieu-Daudé <philmd@redhat.com>
---
 target/arm/helper.c | 40 ++++++++++++++++++++--------------------
 1 file changed, 20 insertions(+), 20 deletions(-)

diff --git a/target/arm/helper.c b/target/arm/helper.c
index a829086c6d..b4fd9b42d7 100644
--- a/target/arm/helper.c
+++ b/target/arm/helper.c
@@ -7923,26 +7923,6 @@ 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 pointer.
-     */
-    bool new_is_psp, old_is_psp = v7m_using_psp(env);
-    uint32_t tmp;
-
-    env->v7m.exception = new_exc;
-
-    new_is_psp = v7m_using_psp(env);
-
-    if (old_is_psp != new_is_psp) {
-        tmp = env->v7m.other_sp;
-        env->v7m.other_sp = env->regs[13];
-        env->regs[13] = tmp;
-    }
-}
-
 /* Switch M profile security state between NS and S */
 void switch_v7m_security_state(CPUARMState *env, bool new_secstate)
 {
@@ -9247,6 +9227,26 @@ static bool do_v7m_function_return(ARMCPU *cpu)
     return true;
 }
 
+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 pointer.
+     */
+    bool new_is_psp, old_is_psp = v7m_using_psp(env);
+    uint32_t tmp;
+
+    env->v7m.exception = new_exc;
+
+    new_is_psp = v7m_using_psp(env);
+
+    if (old_is_psp != new_is_psp) {
+        tmp = env->v7m.other_sp;
+        env->v7m.other_sp = env->regs[13];
+        env->regs[13] = tmp;
+    }
+}
+
 void arm_log_exception(int idx)
 {
     if (qemu_loglevel_mask(CPU_LOG_INT)) {
-- 
2.20.1



^ permalink raw reply related	[flat|nested] 51+ messages in thread

* [Qemu-devel] [PATCH v2 10/23] target/arm: Move the v7-M Security State helpers to v7m_helper
  2019-06-15 15:43 [Qemu-devel] [PATCH v2 00/23] Support disabling TCG on ARM Philippe Mathieu-Daudé
                   ` (8 preceding siblings ...)
  2019-06-15 15:43 ` [Qemu-devel] [PATCH v2 09/23] target/arm: Move code around Philippe Mathieu-Daudé
@ 2019-06-15 15:43 ` Philippe Mathieu-Daudé
  2019-06-17 14:08   ` [Qemu-devel] [Qemu-arm] " Alex Bennée
  2019-06-15 15:43 ` [Qemu-devel] [PATCH v2 11/23] target/arm: Declare v7m_cpacr_pass() publicly Philippe Mathieu-Daudé
                   ` (12 subsequent siblings)
  22 siblings, 1 reply; 51+ messages in thread
From: Philippe Mathieu-Daudé @ 2019-06-15 15:43 UTC (permalink / raw)
  To: qemu-devel; +Cc: Peter Maydell, qemu-arm, Philippe Mathieu-Daudé

Signed-off-by: Philippe Mathieu-Daudé <philmd@redhat.com>
---
 target/arm/helper.c     | 73 -----------------------------------------
 target/arm/v7m_helper.c | 73 +++++++++++++++++++++++++++++++++++++++++
 2 files changed, 73 insertions(+), 73 deletions(-)

diff --git a/target/arm/helper.c b/target/arm/helper.c
index b4fd9b42d7..cf76010ea1 100644
--- a/target/arm/helper.c
+++ b/target/arm/helper.c
@@ -7885,79 +7885,6 @@ void HELPER(v7m_preserve_fp_state)(CPUARMState *env)
      */
 }
 
-/*
- * 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.
- */
-void write_v7m_control_spsel_for_secstate(CPUARMState *env,
-                                          bool new_spsel,
-                                          bool secstate)
-{
-    bool old_is_psp = v7m_using_psp(env);
-
-    env->v7m.control[secstate] =
-        deposit32(env->v7m.control[secstate],
-                  R_V7M_CONTROL_SPSEL_SHIFT,
-                  R_V7M_CONTROL_SPSEL_LENGTH, new_spsel);
-
-    if (secstate == env->v7m.secure) {
-        bool new_is_psp = v7m_using_psp(env);
-        uint32_t tmp;
-
-        if (old_is_psp != new_is_psp) {
-            tmp = env->v7m.other_sp;
-            env->v7m.other_sp = env->regs[13];
-            env->regs[13] = tmp;
-        }
-    }
-}
-
-/*
- * Write to v7M CONTROL.SPSEL bit. This may change the current
- * stack pointer between Main and Process stack pointers.
- */
-void write_v7m_control_spsel(CPUARMState *env, bool new_spsel)
-{
-    write_v7m_control_spsel_for_secstate(env, new_spsel, env->v7m.secure);
-}
-
-/* Switch M profile security state between NS and S */
-void switch_v7m_security_state(CPUARMState *env, bool new_secstate)
-{
-    uint32_t new_ss_msp, new_ss_psp;
-
-    if (env->v7m.secure == 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 = env->v7m.other_ss_msp;
-    new_ss_psp = env->v7m.other_ss_psp;
-
-    if (v7m_using_psp(env)) {
-        env->v7m.other_ss_psp = env->regs[13];
-        env->v7m.other_ss_msp = env->v7m.other_sp;
-    } else {
-        env->v7m.other_ss_msp = env->regs[13];
-        env->v7m.other_ss_psp = env->v7m.other_sp;
-    }
-
-    env->v7m.secure = new_secstate;
-
-    if (v7m_using_psp(env)) {
-        env->regs[13] = new_ss_psp;
-        env->v7m.other_sp = new_ss_msp;
-    } else {
-        env->regs[13] = new_ss_msp;
-        env->v7m.other_sp = new_ss_psp;
-    }
-}
-
 static uint32_t *get_v7m_sp_ptr(CPUARMState *env, bool secure, bool threadmode,
                                 bool spsel)
 {
diff --git a/target/arm/v7m_helper.c b/target/arm/v7m_helper.c
index 321154966e..558e143039 100644
--- a/target/arm/v7m_helper.c
+++ b/target/arm/v7m_helper.c
@@ -88,6 +88,79 @@ uint32_t HELPER(v7m_tt)(CPUARMState *env, uint32_t addr, uint32_t op)
 
 #else
 
+/*
+ * 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.
+ */
+void write_v7m_control_spsel_for_secstate(CPUARMState *env,
+                                          bool new_spsel,
+                                          bool secstate)
+{
+    bool old_is_psp = v7m_using_psp(env);
+
+    env->v7m.control[secstate] =
+        deposit32(env->v7m.control[secstate],
+                  R_V7M_CONTROL_SPSEL_SHIFT,
+                  R_V7M_CONTROL_SPSEL_LENGTH, new_spsel);
+
+    if (secstate == env->v7m.secure) {
+        bool new_is_psp = v7m_using_psp(env);
+        uint32_t tmp;
+
+        if (old_is_psp != new_is_psp) {
+            tmp = env->v7m.other_sp;
+            env->v7m.other_sp = env->regs[13];
+            env->regs[13] = tmp;
+        }
+    }
+}
+
+/*
+ * Write to v7M CONTROL.SPSEL bit. This may change the current
+ * stack pointer between Main and Process stack pointers.
+ */
+void write_v7m_control_spsel(CPUARMState *env, bool new_spsel)
+{
+    write_v7m_control_spsel_for_secstate(env, new_spsel, env->v7m.secure);
+}
+
+/* Switch M profile security state between NS and S */
+void switch_v7m_security_state(CPUARMState *env, bool new_secstate)
+{
+    uint32_t new_ss_msp, new_ss_psp;
+
+    if (env->v7m.secure == 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 = env->v7m.other_ss_msp;
+    new_ss_psp = env->v7m.other_ss_psp;
+
+    if (v7m_using_psp(env)) {
+        env->v7m.other_ss_psp = env->regs[13];
+        env->v7m.other_ss_msp = env->v7m.other_sp;
+    } else {
+        env->v7m.other_ss_msp = env->regs[13];
+        env->v7m.other_ss_psp = env->v7m.other_sp;
+    }
+
+    env->v7m.secure = new_secstate;
+
+    if (v7m_using_psp(env)) {
+        env->regs[13] = new_ss_psp;
+        env->v7m.other_sp = new_ss_msp;
+    } else {
+        env->regs[13] = new_ss_msp;
+        env->v7m.other_sp = new_ss_psp;
+    }
+}
+
 void HELPER(v7m_bxns)(CPUARMState *env, uint32_t dest)
 {
     /*
-- 
2.20.1



^ permalink raw reply related	[flat|nested] 51+ messages in thread

* [Qemu-devel] [PATCH v2 11/23] target/arm: Declare v7m_cpacr_pass() publicly
  2019-06-15 15:43 [Qemu-devel] [PATCH v2 00/23] Support disabling TCG on ARM Philippe Mathieu-Daudé
                   ` (9 preceding siblings ...)
  2019-06-15 15:43 ` [Qemu-devel] [PATCH v2 10/23] target/arm: Move the v7-M Security State helpers to v7m_helper Philippe Mathieu-Daudé
@ 2019-06-15 15:43 ` Philippe Mathieu-Daudé
  2019-06-17 14:09   ` [Qemu-devel] [Qemu-arm] " Alex Bennée
  2019-06-15 15:43 ` [Qemu-devel] [PATCH v2 12/23] target/arm: Move v7m exception handling routines to v7m_helper Philippe Mathieu-Daudé
                   ` (11 subsequent siblings)
  22 siblings, 1 reply; 51+ messages in thread
From: Philippe Mathieu-Daudé @ 2019-06-15 15:43 UTC (permalink / raw)
  To: qemu-devel; +Cc: Peter Maydell, qemu-arm, Philippe Mathieu-Daudé

In the next commit we will move exception handling routines to
v7m_helper, so this function will be called from 2 different
files. Declare it inlined in the "internals.h" header.

Signed-off-by: Philippe Mathieu-Daudé <philmd@redhat.com>
---
 target/arm/helper.c    | 19 -------------------
 target/arm/internals.h | 21 +++++++++++++++++++++
 2 files changed, 21 insertions(+), 19 deletions(-)

diff --git a/target/arm/helper.c b/target/arm/helper.c
index cf76010ea1..5d05db84d3 100644
--- a/target/arm/helper.c
+++ b/target/arm/helper.c
@@ -7611,25 +7611,6 @@ uint32_t arm_phys_excp_target_el(CPUState *cs, uint32_t excp_idx,
     return target_el;
 }
 
-/*
- * Return true if the v7M CPACR permits access to the FPU for the specified
- * security state and privilege level.
- */
-static bool v7m_cpacr_pass(CPUARMState *env, bool is_secure, bool is_priv)
-{
-    switch (extract32(env->v7m.cpacr[is_secure], 20, 2)) {
-    case 0:
-    case 2: /* UNPREDICTABLE: we treat like 0 */
-        return false;
-    case 1:
-        return is_priv;
-    case 3:
-        return true;
-    default:
-        g_assert_not_reached();
-    }
-}
-
 /*
  * What kind of stack write are we doing? This affects how exceptions
  * generated during the stacking are treated.
diff --git a/target/arm/internals.h b/target/arm/internals.h
index 04711b317a..1d15af3f8b 100644
--- a/target/arm/internals.h
+++ b/target/arm/internals.h
@@ -891,6 +891,27 @@ static inline uint32_t v7m_sp_limit(CPUARMState *env)
     }
 }
 
+/**
+ * v7m_cpacr_pass:
+ * Return true if the v7M CPACR permits access to the FPU for the specified
+ * security state and privilege level.
+ */
+static inline bool v7m_cpacr_pass(CPUARMState *env,
+                                  bool is_secure, bool is_priv)
+{
+    switch (extract32(env->v7m.cpacr[is_secure], 20, 2)) {
+    case 0:
+    case 2: /* UNPREDICTABLE: we treat like 0 */
+        return false;
+    case 1:
+        return is_priv;
+    case 3:
+        return true;
+    default:
+        g_assert_not_reached();
+    }
+}
+
 /**
  * aarch32_mode_name(): Return name of the AArch32 CPU mode
  * @psr: Program Status Register indicating CPU mode
-- 
2.20.1



^ permalink raw reply related	[flat|nested] 51+ messages in thread

* [Qemu-devel] [PATCH v2 12/23] target/arm: Move v7m exception handling routines to v7m_helper
  2019-06-15 15:43 [Qemu-devel] [PATCH v2 00/23] Support disabling TCG on ARM Philippe Mathieu-Daudé
                   ` (10 preceding siblings ...)
  2019-06-15 15:43 ` [Qemu-devel] [PATCH v2 11/23] target/arm: Declare v7m_cpacr_pass() publicly Philippe Mathieu-Daudé
@ 2019-06-15 15:43 ` Philippe Mathieu-Daudé
  2019-06-17 14:10   ` [Qemu-devel] [Qemu-arm] " Alex Bennée
  2019-06-15 15:43 ` [Qemu-devel] [PATCH v2 13/23] target/arm: Make the v7-M Security State routines Philippe Mathieu-Daudé
                   ` (10 subsequent siblings)
  22 siblings, 1 reply; 51+ messages in thread
From: Philippe Mathieu-Daudé @ 2019-06-15 15:43 UTC (permalink / raw)
  To: qemu-devel
  Cc: Peter Maydell, qemu-arm, Philippe Mathieu-Daudé, Samuel Ortiz

From: Samuel Ortiz <sameo@linux.intel.com>

In preparation for supporting TCG disablement on ARM, we move the v7m
exception handling routines to v7m_helper.c
arm_v7m_cpu_do_interrupt pulls a large number of static functions
out of helper.c into m_helper.c because it is TCG dependent.

Signed-off-by: Samuel Ortiz <sameo@linux.intel.com>
[PMD: Patch rewritten]
Signed-off-by: Philippe Mathieu-Daudé <philmd@redhat.com>
---
 target/arm/helper.c     | 1876 ---------------------------------------
 target/arm/v7m_helper.c | 1876 +++++++++++++++++++++++++++++++++++++++
 2 files changed, 1876 insertions(+), 1876 deletions(-)

diff --git a/target/arm/helper.c b/target/arm/helper.c
index 5d05db84d3..24d88eef17 100644
--- a/target/arm/helper.c
+++ b/target/arm/helper.c
@@ -7611,1530 +7611,6 @@ uint32_t arm_phys_excp_target_el(CPUState *cs, uint32_t excp_idx,
     return target_el;
 }
 
-/*
- * 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 = CPU(cpu);
-    CPUARMState *env = &cpu->env;
-    MemTxAttrs attrs = {};
-    MemTxResult txres;
-    target_ulong page_size;
-    hwaddr physaddr;
-    int prot;
-    ARMMMUFaultInfo fi = {};
-    bool secure = 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 == ARMFault_QEMU_SFault) {
-            if (mode == STACK_LAZYFP) {
-                qemu_log_mask(CPU_LOG_INT,
-                              "...SecureFault with SFSR.LSPERR "
-                              "during lazy stacking\n");
-                env->v7m.sfsr |= R_V7M_SFSR_LSPERR_MASK;
-            } else {
-                qemu_log_mask(CPU_LOG_INT,
-                              "...SecureFault with SFSR.AUVIOL "
-                              "during stacking\n");
-                env->v7m.sfsr |= R_V7M_SFSR_AUVIOL_MASK;
-            }
-            env->v7m.sfsr |= R_V7M_SFSR_SFARVALID_MASK;
-            env->v7m.sfar = addr;
-            exc = ARMV7M_EXCP_SECURE;
-            exc_secure = false;
-        } else {
-            if (mode == STACK_LAZYFP) {
-                qemu_log_mask(CPU_LOG_INT,
-                              "...MemManageFault with CFSR.MLSPERR\n");
-                env->v7m.cfsr[secure] |= R_V7M_CFSR_MLSPERR_MASK;
-            } else {
-                qemu_log_mask(CPU_LOG_INT,
-                              "...MemManageFault with CFSR.MSTKERR\n");
-                env->v7m.cfsr[secure] |= R_V7M_CFSR_MSTKERR_MASK;
-            }
-            exc = ARMV7M_EXCP_MEM;
-            exc_secure = secure;
-        }
-        goto pend_fault;
-    }
-    address_space_stl_le(arm_addressspace(cs, attrs), physaddr, value,
-                         attrs, &txres);
-    if (txres != MEMTX_OK) {
-        /* BusFault trying to write the data */
-        if (mode == STACK_LAZYFP) {
-            qemu_log_mask(CPU_LOG_INT, "...BusFault with BFSR.LSPERR\n");
-            env->v7m.cfsr[M_REG_NS] |= R_V7M_CFSR_LSPERR_MASK;
-        } else {
-            qemu_log_mask(CPU_LOG_INT, "...BusFault with BFSR.STKERR\n");
-            env->v7m.cfsr[M_REG_NS] |= R_V7M_CFSR_STKERR_MASK;
-        }
-        exc = ARMV7M_EXCP_BUS;
-        exc_secure = 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 = CPU(cpu);
-    CPUARMState *env = &cpu->env;
-    MemTxAttrs attrs = {};
-    MemTxResult txres;
-    target_ulong page_size;
-    hwaddr physaddr;
-    int prot;
-    ARMMMUFaultInfo fi = {};
-    bool secure = 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 == ARMFault_QEMU_SFault) {
-            qemu_log_mask(CPU_LOG_INT,
-                          "...SecureFault with SFSR.AUVIOL during unstack\n");
-            env->v7m.sfsr |= R_V7M_SFSR_AUVIOL_MASK | R_V7M_SFSR_SFARVALID_MASK;
-            env->v7m.sfar = addr;
-            exc = ARMV7M_EXCP_SECURE;
-            exc_secure = false;
-        } else {
-            qemu_log_mask(CPU_LOG_INT,
-                          "...MemManageFault with CFSR.MUNSTKERR\n");
-            env->v7m.cfsr[secure] |= R_V7M_CFSR_MUNSTKERR_MASK;
-            exc = ARMV7M_EXCP_MEM;
-            exc_secure = secure;
-        }
-        goto pend_fault;
-    }
-
-    value = address_space_ldl(arm_addressspace(cs, attrs), physaddr,
-                              attrs, &txres);
-    if (txres != 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] |= R_V7M_CFSR_UNSTKERR_MASK;
-        exc = ARMV7M_EXCP_BUS;
-        exc_secure = false;
-        goto pend_fault;
-    }
-
-    *dest = 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 = env_archcpu(env);
-    bool is_secure = env->v7m.fpccr[M_REG_S] & R_V7M_FPCCR_S_MASK;
-    bool negpri = !(env->v7m.fpccr[M_REG_S] & R_V7M_FPCCR_HFRDY_MASK);
-    bool is_priv = !(env->v7m.fpccr[is_secure] & R_V7M_FPCCR_USER_MASK);
-    bool splimviol = env->v7m.fpccr[is_secure] & R_V7M_FPCCR_SPLIMVIOL_MASK;
-    uint32_t fpcar = env->v7m.fpcar[is_secure];
-    bool stacked_ok = true;
-    bool ts = is_secure && (env->v7m.fpccr[M_REG_S] & R_V7M_FPCCR_TS_MASK);
-    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_secure);
-        env->v7m.cfsr[is_secure] |= R_V7M_CFSR_NOCP_MASK;
-        stacked_ok = 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] |= R_V7M_CFSR_NOCP_MASK;
-        stacked_ok = false;
-    }
-
-    if (!splimviol && stacked_ok) {
-        /* We only stack if the stack limit wasn't violated */
-        int i;
-        ARMMMUIdx mmu_idx;
-
-        mmu_idx = arm_v7m_mmu_idx_all(env, is_secure, is_priv, negpri);
-        for (i = 0; i < (ts ? 32 : 16); i += 2) {
-            uint64_t dn = *aa32_vfp_dreg(env, i / 2);
-            uint32_t faddr = fpcar + 4 * i;
-            uint32_t slo = extract64(dn, 0, 32);
-            uint32_t shi = extract64(dn, 32, 32);
-
-            if (i >= 16) {
-                faddr += 8; /* skip the slot for the FPSCR */
-            }
-            stacked_ok = 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 = 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 = !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] &= ~R_V7M_FPCCR_LSPACT_MASK;
-
-    if (ts) {
-        /* Clear s0 to s31 and the FPSCR */
-        int i;
-
-        for (i = 0; i < 32; i += 2) {
-            *aa32_vfp_dreg(env, i / 2) = 0;
-        }
-        vfp_set_fpscr(env, 0);
-    }
-    /*
-     * Otherwise s0 to s15 and FPSCR are UNKNOWN; we choose to leave them
-     * unchanged.
-     */
-}
-
-static uint32_t *get_v7m_sp_ptr(CPUARMState *env, bool secure, bool threadmode,
-                                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 = threadmode && spsel;
-
-    if (secure == env->v7m.secure) {
-        if (want_psp == 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 = CPU(cpu);
-    CPUARMState *env = &cpu->env;
-    MemTxResult result;
-    uint32_t addr = env->v7m.vecbase[targets_secure] + exc * 4;
-    uint32_t vector_entry;
-    MemTxAttrs attrs = {};
-    ARMMMUIdx mmu_idx;
-    bool exc_secure;
-
-    mmu_idx = 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 = targets_secure;
-    attrs.user = false;
-
-    if (arm_feature(env, ARM_FEATURE_M_SECURITY)) {
-        V8M_SAttributes sattrs = {};
-
-        v8m_security_lookup(env, addr, MMU_DATA_LOAD, mmu_idx, &sattrs);
-        if (sattrs.ns) {
-            attrs.secure = false;
-        } else if (!targets_secure) {
-            /* NS access to S memory */
-            goto load_fail;
-        }
-    }
-
-    vector_entry = address_space_ldl(arm_addressspace(cs, attrs), addr,
-                                     attrs, &result);
-    if (result != MEMTX_OK) {
-        goto load_fail;
-    }
-    *pvec = 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_derived()).
-     */
-    exc_secure = targets_secure ||
-        !(cpu->env.v7m.aircr & R_V7M_AIRCR_BFHFNMINS_MASK);
-    env->v7m.hfsr |= R_V7M_HFSR_VECTTBL_MASK | R_V7M_HFSR_FORCED_MASK;
-    armv7m_nvic_set_pending_derived(env->nvic, ARMV7M_EXCP_HARD, exc_secure);
-    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 = 0xfefa125a;
-
-    if (!arm_feature(env, ARM_FEATURE_VFP) || (lr & R_V7M_EXCRET_FTYPE_MASK)) {
-        sig |= 1;
-    }
-    return sig;
-}
-
-static bool v7m_push_callee_stack(ARMCPU *cpu, uint32_t lr, bool dotailchain,
-                                  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 = &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 = ignore_faults ? STACK_IGNFAULTS : STACK_NORMAL;
-
-    if (dotailchain) {
-        bool mode = lr & R_V7M_EXCRET_MODE_MASK;
-        bool priv = !(env->v7m.control[M_REG_S] & R_V7M_CONTROL_NPRIV_MASK) ||
-            !mode;
-
-        mmu_idx = arm_v7m_mmu_idx_for_secstate_and_priv(env, M_REG_S, priv);
-        frame_sp_p = get_v7m_sp_ptr(env, M_REG_S, mode,
-                                    lr & R_V7M_EXCRET_SPSEL_MASK);
-        want_psp = mode && (lr & R_V7M_EXCRET_SPSEL_MASK);
-        if (want_psp) {
-            limit = env->v7m.psplim[M_REG_S];
-        } else {
-            limit = env->v7m.msplim[M_REG_S];
-        }
-    } else {
-        mmu_idx = arm_mmu_idx(env);
-        frame_sp_p = &env->regs[13];
-        limit = v7m_sp_limit(env);
-    }
-
-    frameptr = *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] |= R_V7M_CFSR_STKOF_MASK;
-        armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_USAGE,
-                                env->v7m.secure);
-        *frame_sp_p = 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 = v7m_integrity_sig(env, lr);
-    stacked_ok =
-        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, smode) &&
-        v7m_stack_write(cpu, frameptr + 0x24, env->regs[11], mmu_idx, smode);
-
-    /* Update SP regardless of whether any of the stack accesses failed. */
-    *frame_sp_p = 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 = &cpu->env;
-    uint32_t addr;
-    bool targets_secure;
-    int exc;
-    bool push_failed = 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 |= R_V7M_EXCRET_FTYPE_MASK;
-        }
-        lr = 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 &= ~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 = v7m_push_callee_stack(cpu, lr, dotailchain,
-                                                        ignore_stackfaults);
-                }
-                lr |= R_V7M_EXCRET_DCRS_MASK;
-            }
-        }
-
-        lr &= ~R_V7M_EXCRET_ES_MASK;
-        if (targets_secure || !arm_feature(env, ARM_FEATURE_M_SECURITY)) {
-            lr |= R_V7M_EXCRET_ES_MASK;
-        }
-        lr &= ~R_V7M_EXCRET_SPSEL_MASK;
-        if (env->v7m.control[targets_secure] & R_V7M_CONTROL_SPSEL_MASK) {
-            lr |= 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 = 0; i < 13; i++) {
-                    /* r4..r11 are callee-saves, zero only if EXCRET.S == 1 */
-                    if (i < 4 || i > 11 || (lr & R_V7M_EXCRET_S_MASK)) {
-                        env->regs[i] = 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 stacking");
-        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 load");
-        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 SPSEL */
-    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] &=
-        ~(R_V7M_CONTROL_FPCA_MASK | R_V7M_CONTROL_SFPA_MASK);
-    /* Clear IT bits */
-    env->condexec_bits = 0;
-    env->regs[14] = lr;
-    env->regs[15] = addr & 0xfffffffe;
-    env->thumb = 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 = env->v7m.secure;
-    void *nvic = 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 = &env->v7m.fpccr[M_REG_S];
-    uint32_t *fpccr_ns = &env->v7m.fpccr[M_REG_NS];
-    uint32_t *fpccr = &env->v7m.fpccr[is_secure];
-    bool hfrdy, bfrdy, mmrdy, ns_ufrdy, s_ufrdy, sfrdy, monrdy;
-
-    env->v7m.fpcar[is_secure] = frameptr & ~0x7;
-
-    if (apply_splim && arm_feature(env, ARM_FEATURE_V8)) {
-        bool splimviol;
-        uint32_t splim = v7m_sp_limit(env);
-        bool ign = armv7m_nvic_neg_prio_requested(nvic, is_secure) &&
-            (env->v7m.ccr[is_secure] & R_V7M_CCR_STKOFHFNMIGN_MASK);
-
-        splimviol = !ign && frameptr < splim;
-        *fpccr = FIELD_DP32(*fpccr, V7M_FPCCR, SPLIMVIOL, splimviol);
-    }
-
-    *fpccr = FIELD_DP32(*fpccr, V7M_FPCCR, LSPACT, 1);
-
-    *fpccr_s = FIELD_DP32(*fpccr_s, V7M_FPCCR, S, is_secure);
-
-    *fpccr = FIELD_DP32(*fpccr, V7M_FPCCR, USER, arm_current_el(env) == 0);
-
-    *fpccr = FIELD_DP32(*fpccr, V7M_FPCCR, THREAD,
-                        !arm_v7m_is_handler_mode(env));
-
-    hfrdy = armv7m_nvic_get_ready_status(nvic, ARMV7M_EXCP_HARD, false);
-    *fpccr_s = FIELD_DP32(*fpccr_s, V7M_FPCCR, HFRDY, hfrdy);
-
-    bfrdy = armv7m_nvic_get_ready_status(nvic, ARMV7M_EXCP_BUS, false);
-    *fpccr_s = FIELD_DP32(*fpccr_s, V7M_FPCCR, BFRDY, bfrdy);
-
-    mmrdy = armv7m_nvic_get_ready_status(nvic, ARMV7M_EXCP_MEM, is_secure);
-    *fpccr = FIELD_DP32(*fpccr, V7M_FPCCR, MMRDY, mmrdy);
-
-    ns_ufrdy = armv7m_nvic_get_ready_status(nvic, ARMV7M_EXCP_USAGE, false);
-    *fpccr_ns = FIELD_DP32(*fpccr_ns, V7M_FPCCR, UFRDY, ns_ufrdy);
-
-    monrdy = armv7m_nvic_get_ready_status(nvic, ARMV7M_EXCP_DEBUG, false);
-    *fpccr_s = FIELD_DP32(*fpccr_s, V7M_FPCCR, MONRDY, monrdy);
-
-    if (arm_feature(env, ARM_FEATURE_M_SECURITY)) {
-        s_ufrdy = armv7m_nvic_get_ready_status(nvic, ARMV7M_EXCP_USAGE, true);
-        *fpccr_s = FIELD_DP32(*fpccr_s, V7M_FPCCR, UFRDY, s_ufrdy);
-
-        sfrdy = armv7m_nvic_get_ready_status(nvic, ARMV7M_EXCP_SECURE, false);
-        *fpccr_s = 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 = env->v7m.fpccr[M_REG_S] & R_V7M_FPCCR_S_MASK;
-    bool lspact = 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) != 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_STACK
-     * 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 = env->v7m.fpccr[M_REG_S] & R_V7M_FPCCR_TS_MASK;
-        int i;
-
-        for (i = 0; i < (ts ? 32 : 16); i += 2) {
-            uint64_t dn = *aa32_vfp_dreg(env, i / 2);
-            uint32_t faddr = fptr + 4 * i;
-            uint32_t slo = extract64(dn, 0, 32);
-            uint32_t shi = extract64(dn, 32, 32);
-
-            if (i >= 16) {
-                faddr += 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_state.
-         */
-        if (ts) {
-            for (i = 0; i < 32; i += 2) {
-                *aa32_vfp_dreg(env, i / 2) = 0;
-            }
-            vfp_set_fpscr(env, 0);
-        }
-    } else {
-        v7m_update_fpccr(env, fptr, false);
-    }
-
-    env->v7m.control[M_REG_S] &= ~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) != 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] &= ~R_V7M_FPCCR_LSPACT_MASK;
-    } else {
-        bool ts = 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 = 0; i < (ts ? 32 : 16); i += 2) {
-            uint32_t slo, shi;
-            uint64_t dn;
-            uint32_t faddr = fptr + 4 * i;
-
-            if (i >= 16) {
-                faddr += 8; /* skip the slot for the FPSCR */
-            }
-
-            slo = cpu_ldl_data(env, faddr);
-            shi = cpu_ldl_data(env, faddr + 4);
-
-            dn = (uint64_t) shi << 32 | slo;
-            *aa32_vfp_dreg(env, i / 2) = dn;
-        }
-        fpscr = cpu_ldl_data(env, fptr + 0x40);
-        vfp_set_fpscr(env, fpscr);
-    }
-
-    env->v7m.control[M_REG_S] |= 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 = true, limitviol = false;
-    CPUARMState *env = &cpu->env;
-    uint32_t xpsr = xpsr_read(env);
-    uint32_t frameptr = env->regs[13];
-    ARMMMUIdx mmu_idx = arm_mmu_idx(env);
-    uint32_t framesize;
-    bool nsacr_cp10 = 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 = 0xa8;
-        } else {
-            framesize = 0x68;
-        }
-    } else {
-        framesize = 0x20;
-    }
-
-    /* Align stack pointer if the guest wants that */
-    if ((frameptr & 4) &&
-        (env->v7m.ccr[env->v7m.secure] & R_V7M_CCR_STKALIGN_MASK)) {
-        frameptr -= 4;
-        xpsr |= XPSR_SPREALIGN;
-    }
-
-    xpsr &= ~XPSR_SFPA;
-    if (env->v7m.secure &&
-        (env->v7m.control[M_REG_S] & R_V7M_CONTROL_SFPA_MASK)) {
-        xpsr |= XPSR_SFPA;
-    }
-
-    frameptr -= framesize;
-
-    if (arm_feature(env, ARM_FEATURE_V8)) {
-        uint32_t limit = 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] |= R_V7M_CFSR_STKOF_MASK;
-            armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_USAGE,
-                                    env->v7m.secure);
-            env->regs[13] = 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 = true;
-            stacked_ok = 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 = 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 = env->v7m.fpccr[M_REG_S] & R_V7M_FPCCR_S_MASK;
-        bool lspact = 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 |= 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] |= 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 = v7m_cpacr_pass(env, env->v7m.secure,
-                                                 arm_current_el(env) != 0);
-
-                if (stacked_ok && !cpacr_pass) {
-                    /*
-                     * Take UsageFault if CPACR forbids access. The pseudocode
-                     * here does a full CheckCPEnabled() but we know the NSACR
-                     * check can never fail as we have already handled that.
-                     */
-                    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] |= R_V7M_CFSR_NOCP_MASK;
-                    stacked_ok = false;
-                }
-
-                for (i = 0; i < ((framesize == 0xa8) ? 32 : 16); i += 2) {
-                    uint64_t dn = *aa32_vfp_dreg(env, i / 2);
-                    uint32_t faddr = frameptr + 0x20 + 4 * i;
-                    uint32_t slo = extract64(dn, 0, 32);
-                    uint32_t shi = extract64(dn, 32, 32);
-
-                    if (i >= 16) {
-                        faddr += 8; /* skip the slot for the FPSCR */
-                    }
-                    stacked_ok = 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 = stacked_ok &&
-                    v7m_stack_write(cpu, frameptr + 0x60,
-                                    vfp_get_fpscr(env), mmu_idx, STACK_NORMAL);
-                if (cpacr_pass) {
-                    for (i = 0; i < ((framesize == 0xa8) ? 32 : 16); i += 2) {
-                        *aa32_vfp_dreg(env, i / 2) = 0;
-                    }
-                    vfp_set_fpscr(env, 0);
-                }
-            } else {
-                /* Lazy stacking enabled, save necessary info to stack later */
-                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] = frameptr;
-    }
-
-    return !stacked_ok;
-}
-
-static void do_v7m_exception_exit(ARMCPU *cpu)
-{
-    CPUARMState *env = &cpu->env;
-    uint32_t excret;
-    uint32_t xpsr, xpsr_mask;
-    bool ufault = false;
-    bool sfault = false;
-    bool return_to_sp_process;
-    bool return_to_handler;
-    bool rettobase = false;
-    bool exc_secure = 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 = env->regs[15];
-    if (env->thumb) {
-        excret |= 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) != R_V7M_EXCRET_RES1_MASK) {
-        qemu_log_mask(LOG_GUEST_ERROR, "M profile: zero high bits in exception "
-                      "exit PC value 0x%" PRIx32 " are UNPREDICTABLE\n",
-                      excret);
-    }
-
-    ftype = 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 = 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 = 1;
-            /* For all other purposes, treat ES as 0 (R_HXSR) */
-            excret &= ~R_V7M_EXCRET_ES_MASK;
-        }
-        exc_secure = excret & R_V7M_EXCRET_ES_MASK;
-    }
-
-    if (env->v7m.exception != 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 >= 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) >= 0) {
-                env->v7m.faultmask[exc_secure] = 0;
-            }
-        } else {
-            env->v7m.faultmask[M_REG_NS] = 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 = 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 != 1"
-         * where we have 'rettobase == false'.)
-         */
-        rettobase = true;
-        break;
-    default:
-        g_assert_not_reached();
-    }
-
-    return_to_handler = !(excret & R_V7M_EXCRET_MODE_MASK);
-    return_to_sp_process = excret & R_V7M_EXCRET_SPSEL_MASK;
-    return_to_secure = 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 == 1 or DCRS == 0 or ES == 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 = true;
-            }
-        }
-        if (excret & R_V7M_EXCRET_RES0_MASK) {
-            ufault = 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 = true;
-            }
-            break;
-        default:
-            ufault = 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_secure);
-
-    /*
-     * 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 |= 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 deactivation\n");
-            v7m_exception_taken(cpu, excret, true, false);
-            return;
-        } else {
-            /* Clear s0..s15 and FPSCR */
-            int i;
-
-            for (i = 0; i < 16; i += 2) {
-                *aa32_vfp_dreg(env, i / 2) = 0;
-            }
-            vfp_set_fpscr(env, 0);
-        }
-    }
-
-    if (sfault) {
-        env->v7m.sfsr |= 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] |= R_V7M_CFSR_INVPC_MASK;
-        armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_USAGE, env->v7m.secure);
-        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 = get_v7m_sp_ptr(env,
-                                              return_to_secure,
-                                              !return_to_handler,
-                                              return_to_sp_process);
-        uint32_t frameptr = *frame_sp_p;
-        bool pop_ok = true;
-        ARMMMUIdx mmu_idx;
-        bool return_to_priv = return_to_handler ||
-            !(env->v7m.control[return_to_secure] & R_V7M_CONTROL_NPRIV_MASK);
-
-        mmu_idx = arm_v7m_mmu_idx_for_secstate_and_priv(env, return_to_secure,
-                                                        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 SP "
-                          "for destination state is UNPREDICTABLE\n");
-        }
-
-        /* Do we need to pop callee-saved registers? */
-        if (return_to_secure &&
-            ((excret & R_V7M_EXCRET_ES_MASK) == 0 ||
-             (excret & R_V7M_EXCRET_DCRS_MASK) == 0)) {
-            uint32_t actual_sig;
-
-            pop_ok = v7m_stack_read(cpu, &actual_sig, frameptr, mmu_idx);
-
-            if (pop_ok && v7m_integrity_sig(env, excret) != actual_sig) {
-                /* Take a SecureFault on the current stack */
-                env->v7m.sfsr |= R_V7M_SFSR_INVIS_MASK;
-                armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_SECURE, false);
-                qemu_log_mask(CPU_LOG_INT, "...taking SecureFault on existing "
-                              "stackframe: failed exception return integrity "
-                              "signature check\n");
-                v7m_exception_taken(cpu, excret, true, false);
-                return;
-            }
-
-            pop_ok = 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_idx) &&
-                v7m_stack_read(cpu, &env->regs[7], frameptr + 0x14, mmu_idx) &&
-                v7m_stack_read(cpu, &env->regs[8], frameptr + 0x18, mmu_idx) &&
-                v7m_stack_read(cpu, &env->regs[9], frameptr + 0x1c, mmu_idx) &&
-                v7m_stack_read(cpu, &env->regs[10], frameptr + 0x20, mmu_idx) &&
-                v7m_stack_read(cpu, &env->regs[11], frameptr + 0x24, mmu_idx);
-
-            frameptr += 0x28;
-        }
-
-        /* Pop registers */
-        pop_ok = 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 specified
-         * to be UNPREDICTABLE. In practice actual v7M hardware seems to ignore
-         * the lsbit, and there are several RTOSes out there which incorrectly
-         * 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, but
-         * complain about the badly behaved guest.
-         */
-        if (env->regs[15] & 1) {
-            env->regs[15] &= ~1U;
-            if (!arm_feature(env, ARM_FEATURE_V8)) {
-                qemu_log_mask(LOG_GUEST_ERROR,
-                              "M profile return from interrupt with misaligned "
-                              "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 = (xpsr & XPSR_EXCP) != 0;
-            if (return_to_handler != will_be_handler) {
-                /*
-                 * Take an INVPC UsageFault on the current stack.
-                 * By this point we will have switched to the security state
-                 * 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] |= R_V7M_CFSR_INVPC_MASK;
-                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;
-            }
-        }
-
-        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, false);
-                env->v7m.sfsr |= R_V7M_SFSR_LSERR_MASK;
-                qemu_log_mask(CPU_LOG_INT,
-                              "...taking SecureFault on existing stackframe: "
-                              "Secure LSPACT set but exception return is "
-                              "not to secure state\n");
-                v7m_exception_taken(cpu, excret, true, false);
-                return;
-            }
-
-            restore_s16_s31 = 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] &= ~R_V7M_FPCCR_LSPACT_MASK;
-            } else {
-                int i;
-                uint32_t fpscr;
-                bool cpacr_pass, nsacr_pass;
-
-                cpacr_pass = v7m_cpacr_pass(env, return_to_secure,
-                                            return_to_priv);
-                nsacr_pass = 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] |= R_V7M_CFSR_NOCP_MASK;
-                    qemu_log_mask(CPU_LOG_INT,
-                                  "...taking UsageFault on existing "
-                                  "stackframe: CPACR.CP10 prevents unstacking "
-                                  "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] |= R_V7M_CFSR_INVPC_MASK;
-                    qemu_log_mask(CPU_LOG_INT,
-                                  "...taking Secure UsageFault on existing "
-                                  "stackframe: NSACR.CP10 prevents unstacking "
-                                  "FP regs\n");
-                    v7m_exception_taken(cpu, excret, true, false);
-                    return;
-                }
-
-                for (i = 0; i < (restore_s16_s31 ? 32 : 16); i += 2) {
-                    uint32_t slo, shi;
-                    uint64_t dn;
-                    uint32_t faddr = frameptr + 0x20 + 4 * i;
-
-                    if (i >= 16) {
-                        faddr += 8; /* Skip the slot for the FPSCR */
-                    }
-
-                    pop_ok = pop_ok &&
-                        v7m_stack_read(cpu, &slo, faddr, mmu_idx) &&
-                        v7m_stack_read(cpu, &shi, faddr + 4, mmu_idx);
-
-                    if (!pop_ok) {
-                        break;
-                    }
-
-                    dn = (uint64_t)shi << 32 | slo;
-                    *aa32_vfp_dreg(env, i / 2) = dn;
-                }
-                pop_ok = 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 = 0; i < (restore_s16_s31 ? 32 : 16); i += 2) {
-                        *aa32_vfp_dreg(env, i / 2) = 0;
-                    }
-                    vfp_set_fpscr(env, 0);
-                }
-            }
-        }
-        env->v7m.control[M_REG_S] = FIELD_DP32(env->v7m.control[M_REG_S],
-                                               V7M_CONTROL, FPCA, !ftype);
-
-        /* Commit to consuming the stack frame */
-        frameptr += 0x20;
-        if (!ftype) {
-            frameptr += 0x48;
-            if (restore_s16_s31) {
-                frameptr += 0x40;
-            }
-        }
-        /*
-         * Undo stack alignment (the SPREALIGN bit indicates that the original
-         * 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. (Adding 4
-         * would work too but a logical OR is how the pseudocode specifies it.)
-         */
-        if (xpsr & XPSR_SPREALIGN) {
-            frameptr |= 4;
-        }
-        *frame_sp_p = frameptr;
-    }
-
-    xpsr_mask = ~(XPSR_SPREALIGN | XPSR_SFPA);
-    if (!arm_feature(env, ARM_FEATURE_THUMB_DSP)) {
-        xpsr_mask &= ~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 = xpsr & XPSR_SFPA;
-
-        env->v7m.control[M_REG_S] = 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 != 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] |= R_V7M_CFSR_INVPC_MASK;
-        ignore_stackfaults = 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 = &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 = !arm_v7m_is_handler_mode(env);
-        spsel = env->v7m.control[M_REG_S] & R_V7M_CONTROL_SPSEL_MASK;
-
-        frame_sp_p = get_v7m_sp_ptr(env, true, threadmode, spsel);
-        frameptr = *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 = arm_v7m_mmu_idx_for_secstate(env, true);
-        oi = make_memop_idx(MO_LE, arm_to_core_mmu_idx(mmu_idx));
-        newpc = helper_le_ldul_mmu(env, frameptr, oi, 0);
-        newpsr = helper_le_ldul_mmu(env, frameptr + 4, oi, 0);
-
-        /* Consistency checks on new IPSR */
-        newpsr_exc = newpsr & XPSR_EXCP;
-        if (!((env->v7m.exception == 0 && newpsr_exc == 0) ||
-              (env->v7m.exception == 1 && newpsr_exc != 0))) {
-            /* Pend the fault and tell our caller to take it */
-            env->v7m.cfsr[env->v7m.secure] |= 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 = frameptr + 8;
-    }
-
-    /* This invalidates frame_sp_p */
-    switch_v7m_security_state(env, true);
-    env->v7m.exception = newpsr_exc;
-    env->v7m.control[M_REG_S] &= ~R_V7M_CONTROL_SFPA_MASK;
-    if (newpsr & XPSR_SFPA) {
-        env->v7m.control[M_REG_S] |= R_V7M_CONTROL_SFPA_MASK;
-    }
-    xpsr_write(env, 0, XPSR_IT);
-    env->thumb = newpc & 1;
-    env->regs[15] = newpc & ~1;
-
-    qemu_log_mask(CPU_LOG_INT, "...function return successful\n");
-    return true;
-}
-
 void write_v7m_exception(CPUARMState *env, uint32_t new_exc)
 {
     /*
@@ -9193,358 +7669,6 @@ void arm_log_exception(int idx)
     }
 }
 
-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 success,
-     * or false on failure (in which case we will have pended the appropriate
-     * 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 = CPU(cpu);
-    CPUARMState *env = &cpu->env;
-    V8M_SAttributes sattrs = {};
-    MemTxAttrs attrs = {};
-    ARMMMUFaultInfo fi = {};
-    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 |= 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] |= R_V7M_CFSR_IACCVIOL_MASK;
-        armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_MEM, env->v7m.secure);
-        qemu_log_mask(CPU_LOG_INT, "...really MemManage with CFSR.IACCVIOL\n");
-        return false;
-    }
-    *insn = address_space_lduw_le(arm_addressspace(cs, attrs), physaddr,
-                                 attrs, &txres);
-    if (txres != MEMTX_OK) {
-        env->v7m.cfsr[M_REG_NS] |= 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 = &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 = 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 != 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 != 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" PRIx32
-                  ", executing it\n", env->regs[15]);
-    env->regs[14] &= ~1;
-    env->v7m.control[M_REG_S] &= ~R_V7M_CONTROL_SFPA_MASK;
-    switch_v7m_security_state(env, true);
-    xpsr_write(env, 0, XPSR_IT);
-    env->regs[15] += 4;
-    return true;
-
-gen_invep:
-    env->v7m.sfsr |= 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 = ARM_CPU(cs);
-    CPUARMState *env = &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.secure);
-        env->v7m.cfsr[env->v7m.secure] |= 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 == 3) {
-            target_secstate = M_REG_S;
-        } else {
-            target_secstate = env->v7m.secure;
-        }
-        armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_USAGE, target_secstate);
-        env->v7m.cfsr[target_secstate] |= R_V7M_CFSR_NOCP_MASK;
-        break;
-    }
-    case EXCP_INVSTATE:
-        armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_USAGE, env->v7m.secure);
-        env->v7m.cfsr[env->v7m.secure] |= R_V7M_CFSR_INVSTATE_MASK;
-        break;
-    case EXCP_STKOF:
-        armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_USAGE, env->v7m.secure);
-        env->v7m.cfsr[env->v7m.secure] |= R_V7M_CFSR_STKOF_MASK;
-        break;
-    case EXCP_LSERR:
-        armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_SECURE, false);
-        env->v7m.sfsr |= R_V7M_SFSR_LSERR_MASK;
-        break;
-    case EXCP_UNALIGNED:
-        armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_USAGE, env->v7m.secure);
-        env->v7m.cfsr[env->v7m.secure] |= 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.secure);
-        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 address
-             * 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 |= R_V7M_SFSR_INVTRAN_MASK;
-                    qemu_log_mask(CPU_LOG_INT,
-                                  "...really SecureFault with SFSR.INVTRAN\n");
-                } else {
-                    env->v7m.sfsr |= 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 |= 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] |= 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] |=
-                    (R_V7M_CFSR_PRECISERR_MASK | R_V7M_CFSR_BFARVALID_MASK);
-                env->v7m.bfar = 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] |= R_V7M_CFSR_IACCVIOL_MASK;
-                qemu_log_mask(CPU_LOG_INT, "...with CFSR.IACCVIOL\n");
-                break;
-            case EXCP_DATA_ABORT:
-                env->v7m.cfsr[env->v7m.secure] |=
-                    (R_V7M_CFSR_DACCVIOL_MASK | R_V7M_CFSR_MMARVALID_MASK);
-                env->v7m.mmfar[env->v7m.secure] = env->exception.vaddress;
-                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 = arm_lduw_code(env, env->regs[15], arm_sctlr_b(env)) & 0xff;
-            if (nr == 0xab) {
-                env->regs[15] += 2;
-                qemu_log_mask(CPU_LOG_INT,
-                              "...handling as semihosting call 0x%x\n",
-                              env->regs[0]);
-                env->regs[0] = 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] >= 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 = 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 |= R_V7M_EXCRET_S_MASK;
-        }
-        if (!(env->v7m.control[M_REG_S] & R_V7M_CONTROL_FPCA_MASK)) {
-            lr |= R_V7M_EXCRET_FTYPE_MASK;
-        }
-    } else {
-        lr = 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 |= R_V7M_EXCRET_SPSEL_MASK;
-        }
-    }
-    if (!arm_v7m_is_handler_mode(env)) {
-        lr |= R_V7M_EXCRET_MODE_MASK;
-    }
-
-    ignore_stackfaults = 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 AArch64
  * execution state.
diff --git a/target/arm/v7m_helper.c b/target/arm/v7m_helper.c
index 558e143039..b50bb98e06 100644
--- a/target/arm/v7m_helper.c
+++ b/target/arm/v7m_helper.c
@@ -724,4 +724,1880 @@ uint32_t HELPER(v7m_tt)(CPUARMState *env, uint32_t addr, uint32_t op)
     return tt_resp;
 }
 
+/*
+ * 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 = CPU(cpu);
+    CPUARMState *env = &cpu->env;
+    MemTxAttrs attrs = {};
+    MemTxResult txres;
+    target_ulong page_size;
+    hwaddr physaddr;
+    int prot;
+    ARMMMUFaultInfo fi = {};
+    bool secure = 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 == ARMFault_QEMU_SFault) {
+            if (mode == STACK_LAZYFP) {
+                qemu_log_mask(CPU_LOG_INT,
+                              "...SecureFault with SFSR.LSPERR "
+                              "during lazy stacking\n");
+                env->v7m.sfsr |= R_V7M_SFSR_LSPERR_MASK;
+            } else {
+                qemu_log_mask(CPU_LOG_INT,
+                              "...SecureFault with SFSR.AUVIOL "
+                              "during stacking\n");
+                env->v7m.sfsr |= R_V7M_SFSR_AUVIOL_MASK;
+            }
+            env->v7m.sfsr |= R_V7M_SFSR_SFARVALID_MASK;
+            env->v7m.sfar = addr;
+            exc = ARMV7M_EXCP_SECURE;
+            exc_secure = false;
+        } else {
+            if (mode == STACK_LAZYFP) {
+                qemu_log_mask(CPU_LOG_INT,
+                              "...MemManageFault with CFSR.MLSPERR\n");
+                env->v7m.cfsr[secure] |= R_V7M_CFSR_MLSPERR_MASK;
+            } else {
+                qemu_log_mask(CPU_LOG_INT,
+                              "...MemManageFault with CFSR.MSTKERR\n");
+                env->v7m.cfsr[secure] |= R_V7M_CFSR_MSTKERR_MASK;
+            }
+            exc = ARMV7M_EXCP_MEM;
+            exc_secure = secure;
+        }
+        goto pend_fault;
+    }
+    address_space_stl_le(arm_addressspace(cs, attrs), physaddr, value,
+                         attrs, &txres);
+    if (txres != MEMTX_OK) {
+        /* BusFault trying to write the data */
+        if (mode == STACK_LAZYFP) {
+            qemu_log_mask(CPU_LOG_INT, "...BusFault with BFSR.LSPERR\n");
+            env->v7m.cfsr[M_REG_NS] |= R_V7M_CFSR_LSPERR_MASK;
+        } else {
+            qemu_log_mask(CPU_LOG_INT, "...BusFault with BFSR.STKERR\n");
+            env->v7m.cfsr[M_REG_NS] |= R_V7M_CFSR_STKERR_MASK;
+        }
+        exc = ARMV7M_EXCP_BUS;
+        exc_secure = 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 = CPU(cpu);
+    CPUARMState *env = &cpu->env;
+    MemTxAttrs attrs = {};
+    MemTxResult txres;
+    target_ulong page_size;
+    hwaddr physaddr;
+    int prot;
+    ARMMMUFaultInfo fi = {};
+    bool secure = 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 == ARMFault_QEMU_SFault) {
+            qemu_log_mask(CPU_LOG_INT,
+                          "...SecureFault with SFSR.AUVIOL during unstack\n");
+            env->v7m.sfsr |= R_V7M_SFSR_AUVIOL_MASK | R_V7M_SFSR_SFARVALID_MASK;
+            env->v7m.sfar = addr;
+            exc = ARMV7M_EXCP_SECURE;
+            exc_secure = false;
+        } else {
+            qemu_log_mask(CPU_LOG_INT,
+                          "...MemManageFault with CFSR.MUNSTKERR\n");
+            env->v7m.cfsr[secure] |= R_V7M_CFSR_MUNSTKERR_MASK;
+            exc = ARMV7M_EXCP_MEM;
+            exc_secure = secure;
+        }
+        goto pend_fault;
+    }
+
+    value = address_space_ldl(arm_addressspace(cs, attrs), physaddr,
+                              attrs, &txres);
+    if (txres != 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] |= R_V7M_CFSR_UNSTKERR_MASK;
+        exc = ARMV7M_EXCP_BUS;
+        exc_secure = false;
+        goto pend_fault;
+    }
+
+    *dest = 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 = env_archcpu(env);
+    bool is_secure = env->v7m.fpccr[M_REG_S] & R_V7M_FPCCR_S_MASK;
+    bool negpri = !(env->v7m.fpccr[M_REG_S] & R_V7M_FPCCR_HFRDY_MASK);
+    bool is_priv = !(env->v7m.fpccr[is_secure] & R_V7M_FPCCR_USER_MASK);
+    bool splimviol = env->v7m.fpccr[is_secure] & R_V7M_FPCCR_SPLIMVIOL_MASK;
+    uint32_t fpcar = env->v7m.fpcar[is_secure];
+    bool stacked_ok = true;
+    bool ts = is_secure && (env->v7m.fpccr[M_REG_S] & R_V7M_FPCCR_TS_MASK);
+    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_secure);
+        env->v7m.cfsr[is_secure] |= R_V7M_CFSR_NOCP_MASK;
+        stacked_ok = 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] |= R_V7M_CFSR_NOCP_MASK;
+        stacked_ok = false;
+    }
+
+    if (!splimviol && stacked_ok) {
+        /* We only stack if the stack limit wasn't violated */
+        int i;
+        ARMMMUIdx mmu_idx;
+
+        mmu_idx = arm_v7m_mmu_idx_all(env, is_secure, is_priv, negpri);
+        for (i = 0; i < (ts ? 32 : 16); i += 2) {
+            uint64_t dn = *aa32_vfp_dreg(env, i / 2);
+            uint32_t faddr = fpcar + 4 * i;
+            uint32_t slo = extract64(dn, 0, 32);
+            uint32_t shi = extract64(dn, 32, 32);
+
+            if (i >= 16) {
+                faddr += 8; /* skip the slot for the FPSCR */
+            }
+            stacked_ok = 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 = 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 = !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] &= ~R_V7M_FPCCR_LSPACT_MASK;
+
+    if (ts) {
+        /* Clear s0 to s31 and the FPSCR */
+        int i;
+
+        for (i = 0; i < 32; i += 2) {
+            *aa32_vfp_dreg(env, i / 2) = 0;
+        }
+        vfp_set_fpscr(env, 0);
+    }
+    /*
+     * Otherwise s0 to s15 and FPSCR are UNKNOWN; we choose to leave them
+     * unchanged.
+     */
+}
+
+static uint32_t *get_v7m_sp_ptr(CPUARMState *env, bool secure, bool threadmode,
+                                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 = threadmode && spsel;
+
+    if (secure == env->v7m.secure) {
+        if (want_psp == 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 = CPU(cpu);
+    CPUARMState *env = &cpu->env;
+    MemTxResult result;
+    uint32_t addr = env->v7m.vecbase[targets_secure] + exc * 4;
+    uint32_t vector_entry;
+    MemTxAttrs attrs = {};
+    ARMMMUIdx mmu_idx;
+    bool exc_secure;
+
+    mmu_idx = 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 = targets_secure;
+    attrs.user = false;
+
+    if (arm_feature(env, ARM_FEATURE_M_SECURITY)) {
+        V8M_SAttributes sattrs = {};
+
+        v8m_security_lookup(env, addr, MMU_DATA_LOAD, mmu_idx, &sattrs);
+        if (sattrs.ns) {
+            attrs.secure = false;
+        } else if (!targets_secure) {
+            /* NS access to S memory */
+            goto load_fail;
+        }
+    }
+
+    vector_entry = address_space_ldl(arm_addressspace(cs, attrs), addr,
+                                     attrs, &result);
+    if (result != MEMTX_OK) {
+        goto load_fail;
+    }
+    *pvec = 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_derived()).
+     */
+    exc_secure = targets_secure ||
+        !(cpu->env.v7m.aircr & R_V7M_AIRCR_BFHFNMINS_MASK);
+    env->v7m.hfsr |= R_V7M_HFSR_VECTTBL_MASK | R_V7M_HFSR_FORCED_MASK;
+    armv7m_nvic_set_pending_derived(env->nvic, ARMV7M_EXCP_HARD, exc_secure);
+    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 = 0xfefa125a;
+
+    if (!arm_feature(env, ARM_FEATURE_VFP) || (lr & R_V7M_EXCRET_FTYPE_MASK)) {
+        sig |= 1;
+    }
+    return sig;
+}
+
+static bool v7m_push_callee_stack(ARMCPU *cpu, uint32_t lr, bool dotailchain,
+                                  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 = &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 = ignore_faults ? STACK_IGNFAULTS : STACK_NORMAL;
+
+    if (dotailchain) {
+        bool mode = lr & R_V7M_EXCRET_MODE_MASK;
+        bool priv = !(env->v7m.control[M_REG_S] & R_V7M_CONTROL_NPRIV_MASK) ||
+            !mode;
+
+        mmu_idx = arm_v7m_mmu_idx_for_secstate_and_priv(env, M_REG_S, priv);
+        frame_sp_p = get_v7m_sp_ptr(env, M_REG_S, mode,
+                                    lr & R_V7M_EXCRET_SPSEL_MASK);
+        want_psp = mode && (lr & R_V7M_EXCRET_SPSEL_MASK);
+        if (want_psp) {
+            limit = env->v7m.psplim[M_REG_S];
+        } else {
+            limit = env->v7m.msplim[M_REG_S];
+        }
+    } else {
+        mmu_idx = arm_mmu_idx(env);
+        frame_sp_p = &env->regs[13];
+        limit = v7m_sp_limit(env);
+    }
+
+    frameptr = *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] |= R_V7M_CFSR_STKOF_MASK;
+        armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_USAGE,
+                                env->v7m.secure);
+        *frame_sp_p = 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 = v7m_integrity_sig(env, lr);
+    stacked_ok =
+        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, smode) &&
+        v7m_stack_write(cpu, frameptr + 0x24, env->regs[11], mmu_idx, smode);
+
+    /* Update SP regardless of whether any of the stack accesses failed. */
+    *frame_sp_p = 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 = &cpu->env;
+    uint32_t addr;
+    bool targets_secure;
+    int exc;
+    bool push_failed = 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 |= R_V7M_EXCRET_FTYPE_MASK;
+        }
+        lr = 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 &= ~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 = v7m_push_callee_stack(cpu, lr, dotailchain,
+                                                        ignore_stackfaults);
+                }
+                lr |= R_V7M_EXCRET_DCRS_MASK;
+            }
+        }
+
+        lr &= ~R_V7M_EXCRET_ES_MASK;
+        if (targets_secure || !arm_feature(env, ARM_FEATURE_M_SECURITY)) {
+            lr |= R_V7M_EXCRET_ES_MASK;
+        }
+        lr &= ~R_V7M_EXCRET_SPSEL_MASK;
+        if (env->v7m.control[targets_secure] & R_V7M_CONTROL_SPSEL_MASK) {
+            lr |= 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 = 0; i < 13; i++) {
+                    /* r4..r11 are callee-saves, zero only if EXCRET.S == 1 */
+                    if (i < 4 || i > 11 || (lr & R_V7M_EXCRET_S_MASK)) {
+                        env->regs[i] = 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 stacking");
+        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 load");
+        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 SPSEL */
+    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] &=
+        ~(R_V7M_CONTROL_FPCA_MASK | R_V7M_CONTROL_SFPA_MASK);
+    /* Clear IT bits */
+    env->condexec_bits = 0;
+    env->regs[14] = lr;
+    env->regs[15] = addr & 0xfffffffe;
+    env->thumb = 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 = env->v7m.secure;
+    void *nvic = 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 = &env->v7m.fpccr[M_REG_S];
+    uint32_t *fpccr_ns = &env->v7m.fpccr[M_REG_NS];
+    uint32_t *fpccr = &env->v7m.fpccr[is_secure];
+    bool hfrdy, bfrdy, mmrdy, ns_ufrdy, s_ufrdy, sfrdy, monrdy;
+
+    env->v7m.fpcar[is_secure] = frameptr & ~0x7;
+
+    if (apply_splim && arm_feature(env, ARM_FEATURE_V8)) {
+        bool splimviol;
+        uint32_t splim = v7m_sp_limit(env);
+        bool ign = armv7m_nvic_neg_prio_requested(nvic, is_secure) &&
+            (env->v7m.ccr[is_secure] & R_V7M_CCR_STKOFHFNMIGN_MASK);
+
+        splimviol = !ign && frameptr < splim;
+        *fpccr = FIELD_DP32(*fpccr, V7M_FPCCR, SPLIMVIOL, splimviol);
+    }
+
+    *fpccr = FIELD_DP32(*fpccr, V7M_FPCCR, LSPACT, 1);
+
+    *fpccr_s = FIELD_DP32(*fpccr_s, V7M_FPCCR, S, is_secure);
+
+    *fpccr = FIELD_DP32(*fpccr, V7M_FPCCR, USER, arm_current_el(env) == 0);
+
+    *fpccr = FIELD_DP32(*fpccr, V7M_FPCCR, THREAD,
+                        !arm_v7m_is_handler_mode(env));
+
+    hfrdy = armv7m_nvic_get_ready_status(nvic, ARMV7M_EXCP_HARD, false);
+    *fpccr_s = FIELD_DP32(*fpccr_s, V7M_FPCCR, HFRDY, hfrdy);
+
+    bfrdy = armv7m_nvic_get_ready_status(nvic, ARMV7M_EXCP_BUS, false);
+    *fpccr_s = FIELD_DP32(*fpccr_s, V7M_FPCCR, BFRDY, bfrdy);
+
+    mmrdy = armv7m_nvic_get_ready_status(nvic, ARMV7M_EXCP_MEM, is_secure);
+    *fpccr = FIELD_DP32(*fpccr, V7M_FPCCR, MMRDY, mmrdy);
+
+    ns_ufrdy = armv7m_nvic_get_ready_status(nvic, ARMV7M_EXCP_USAGE, false);
+    *fpccr_ns = FIELD_DP32(*fpccr_ns, V7M_FPCCR, UFRDY, ns_ufrdy);
+
+    monrdy = armv7m_nvic_get_ready_status(nvic, ARMV7M_EXCP_DEBUG, false);
+    *fpccr_s = FIELD_DP32(*fpccr_s, V7M_FPCCR, MONRDY, monrdy);
+
+    if (arm_feature(env, ARM_FEATURE_M_SECURITY)) {
+        s_ufrdy = armv7m_nvic_get_ready_status(nvic, ARMV7M_EXCP_USAGE, true);
+        *fpccr_s = FIELD_DP32(*fpccr_s, V7M_FPCCR, UFRDY, s_ufrdy);
+
+        sfrdy = armv7m_nvic_get_ready_status(nvic, ARMV7M_EXCP_SECURE, false);
+        *fpccr_s = 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 = env->v7m.fpccr[M_REG_S] & R_V7M_FPCCR_S_MASK;
+    bool lspact = 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) != 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_STACK
+     * 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 = env->v7m.fpccr[M_REG_S] & R_V7M_FPCCR_TS_MASK;
+        int i;
+
+        for (i = 0; i < (ts ? 32 : 16); i += 2) {
+            uint64_t dn = *aa32_vfp_dreg(env, i / 2);
+            uint32_t faddr = fptr + 4 * i;
+            uint32_t slo = extract64(dn, 0, 32);
+            uint32_t shi = extract64(dn, 32, 32);
+
+            if (i >= 16) {
+                faddr += 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_state.
+         */
+        if (ts) {
+            for (i = 0; i < 32; i += 2) {
+                *aa32_vfp_dreg(env, i / 2) = 0;
+            }
+            vfp_set_fpscr(env, 0);
+        }
+    } else {
+        v7m_update_fpccr(env, fptr, false);
+    }
+
+    env->v7m.control[M_REG_S] &= ~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) != 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] &= ~R_V7M_FPCCR_LSPACT_MASK;
+    } else {
+        bool ts = 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 = 0; i < (ts ? 32 : 16); i += 2) {
+            uint32_t slo, shi;
+            uint64_t dn;
+            uint32_t faddr = fptr + 4 * i;
+
+            if (i >= 16) {
+                faddr += 8; /* skip the slot for the FPSCR */
+            }
+
+            slo = cpu_ldl_data(env, faddr);
+            shi = cpu_ldl_data(env, faddr + 4);
+
+            dn = (uint64_t) shi << 32 | slo;
+            *aa32_vfp_dreg(env, i / 2) = dn;
+        }
+        fpscr = cpu_ldl_data(env, fptr + 0x40);
+        vfp_set_fpscr(env, fpscr);
+    }
+
+    env->v7m.control[M_REG_S] |= 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 = true, limitviol = false;
+    CPUARMState *env = &cpu->env;
+    uint32_t xpsr = xpsr_read(env);
+    uint32_t frameptr = env->regs[13];
+    ARMMMUIdx mmu_idx = arm_mmu_idx(env);
+    uint32_t framesize;
+    bool nsacr_cp10 = 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 = 0xa8;
+        } else {
+            framesize = 0x68;
+        }
+    } else {
+        framesize = 0x20;
+    }
+
+    /* Align stack pointer if the guest wants that */
+    if ((frameptr & 4) &&
+        (env->v7m.ccr[env->v7m.secure] & R_V7M_CCR_STKALIGN_MASK)) {
+        frameptr -= 4;
+        xpsr |= XPSR_SPREALIGN;
+    }
+
+    xpsr &= ~XPSR_SFPA;
+    if (env->v7m.secure &&
+        (env->v7m.control[M_REG_S] & R_V7M_CONTROL_SFPA_MASK)) {
+        xpsr |= XPSR_SFPA;
+    }
+
+    frameptr -= framesize;
+
+    if (arm_feature(env, ARM_FEATURE_V8)) {
+        uint32_t limit = 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] |= R_V7M_CFSR_STKOF_MASK;
+            armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_USAGE,
+                                    env->v7m.secure);
+            env->regs[13] = 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 = true;
+            stacked_ok = 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 = 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 = env->v7m.fpccr[M_REG_S] & R_V7M_FPCCR_S_MASK;
+        bool lspact = 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 |= 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] |= 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 = v7m_cpacr_pass(env, env->v7m.secure,
+                                                 arm_current_el(env) != 0);
+
+                if (stacked_ok && !cpacr_pass) {
+                    /*
+                     * Take UsageFault if CPACR forbids access. The pseudocode
+                     * here does a full CheckCPEnabled() but we know the NSACR
+                     * check can never fail as we have already handled that.
+                     */
+                    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] |= R_V7M_CFSR_NOCP_MASK;
+                    stacked_ok = false;
+                }
+
+                for (i = 0; i < ((framesize == 0xa8) ? 32 : 16); i += 2) {
+                    uint64_t dn = *aa32_vfp_dreg(env, i / 2);
+                    uint32_t faddr = frameptr + 0x20 + 4 * i;
+                    uint32_t slo = extract64(dn, 0, 32);
+                    uint32_t shi = extract64(dn, 32, 32);
+
+                    if (i >= 16) {
+                        faddr += 8; /* skip the slot for the FPSCR */
+                    }
+                    stacked_ok = 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 = stacked_ok &&
+                    v7m_stack_write(cpu, frameptr + 0x60,
+                                    vfp_get_fpscr(env), mmu_idx, STACK_NORMAL);
+                if (cpacr_pass) {
+                    for (i = 0; i < ((framesize == 0xa8) ? 32 : 16); i += 2) {
+                        *aa32_vfp_dreg(env, i / 2) = 0;
+                    }
+                    vfp_set_fpscr(env, 0);
+                }
+            } else {
+                /* Lazy stacking enabled, save necessary info to stack later */
+                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] = frameptr;
+    }
+
+    return !stacked_ok;
+}
+
+static void do_v7m_exception_exit(ARMCPU *cpu)
+{
+    CPUARMState *env = &cpu->env;
+    uint32_t excret;
+    uint32_t xpsr, xpsr_mask;
+    bool ufault = false;
+    bool sfault = false;
+    bool return_to_sp_process;
+    bool return_to_handler;
+    bool rettobase = false;
+    bool exc_secure = 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 = env->regs[15];
+    if (env->thumb) {
+        excret |= 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) != R_V7M_EXCRET_RES1_MASK) {
+        qemu_log_mask(LOG_GUEST_ERROR, "M profile: zero high bits in exception "
+                      "exit PC value 0x%" PRIx32 " are UNPREDICTABLE\n",
+                      excret);
+    }
+
+    ftype = 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 = 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 = 1;
+            /* For all other purposes, treat ES as 0 (R_HXSR) */
+            excret &= ~R_V7M_EXCRET_ES_MASK;
+        }
+        exc_secure = excret & R_V7M_EXCRET_ES_MASK;
+    }
+
+    if (env->v7m.exception != 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 >= 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) >= 0) {
+                env->v7m.faultmask[exc_secure] = 0;
+            }
+        } else {
+            env->v7m.faultmask[M_REG_NS] = 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 = 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 != 1"
+         * where we have 'rettobase == false'.)
+         */
+        rettobase = true;
+        break;
+    default:
+        g_assert_not_reached();
+    }
+
+    return_to_handler = !(excret & R_V7M_EXCRET_MODE_MASK);
+    return_to_sp_process = excret & R_V7M_EXCRET_SPSEL_MASK;
+    return_to_secure = 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 == 1 or DCRS == 0 or ES == 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 = true;
+            }
+        }
+        if (excret & R_V7M_EXCRET_RES0_MASK) {
+            ufault = 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 = true;
+            }
+            break;
+        default:
+            ufault = 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_secure);
+
+    /*
+     * 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 |= 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 deactivation\n");
+            v7m_exception_taken(cpu, excret, true, false);
+            return;
+        } else {
+            /* Clear s0..s15 and FPSCR */
+            int i;
+
+            for (i = 0; i < 16; i += 2) {
+                *aa32_vfp_dreg(env, i / 2) = 0;
+            }
+            vfp_set_fpscr(env, 0);
+        }
+    }
+
+    if (sfault) {
+        env->v7m.sfsr |= 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] |= R_V7M_CFSR_INVPC_MASK;
+        armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_USAGE, env->v7m.secure);
+        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 = get_v7m_sp_ptr(env,
+                                              return_to_secure,
+                                              !return_to_handler,
+                                              return_to_sp_process);
+        uint32_t frameptr = *frame_sp_p;
+        bool pop_ok = true;
+        ARMMMUIdx mmu_idx;
+        bool return_to_priv = return_to_handler ||
+            !(env->v7m.control[return_to_secure] & R_V7M_CONTROL_NPRIV_MASK);
+
+        mmu_idx = arm_v7m_mmu_idx_for_secstate_and_priv(env, return_to_secure,
+                                                        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 SP "
+                          "for destination state is UNPREDICTABLE\n");
+        }
+
+        /* Do we need to pop callee-saved registers? */
+        if (return_to_secure &&
+            ((excret & R_V7M_EXCRET_ES_MASK) == 0 ||
+             (excret & R_V7M_EXCRET_DCRS_MASK) == 0)) {
+            uint32_t actual_sig;
+
+            pop_ok = v7m_stack_read(cpu, &actual_sig, frameptr, mmu_idx);
+
+            if (pop_ok && v7m_integrity_sig(env, excret) != actual_sig) {
+                /* Take a SecureFault on the current stack */
+                env->v7m.sfsr |= R_V7M_SFSR_INVIS_MASK;
+                armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_SECURE, false);
+                qemu_log_mask(CPU_LOG_INT, "...taking SecureFault on existing "
+                              "stackframe: failed exception return integrity "
+                              "signature check\n");
+                v7m_exception_taken(cpu, excret, true, false);
+                return;
+            }
+
+            pop_ok = 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_idx) &&
+                v7m_stack_read(cpu, &env->regs[7], frameptr + 0x14, mmu_idx) &&
+                v7m_stack_read(cpu, &env->regs[8], frameptr + 0x18, mmu_idx) &&
+                v7m_stack_read(cpu, &env->regs[9], frameptr + 0x1c, mmu_idx) &&
+                v7m_stack_read(cpu, &env->regs[10], frameptr + 0x20, mmu_idx) &&
+                v7m_stack_read(cpu, &env->regs[11], frameptr + 0x24, mmu_idx);
+
+            frameptr += 0x28;
+        }
+
+        /* Pop registers */
+        pop_ok = 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 specified
+         * to be UNPREDICTABLE. In practice actual v7M hardware seems to ignore
+         * the lsbit, and there are several RTOSes out there which incorrectly
+         * 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, but
+         * complain about the badly behaved guest.
+         */
+        if (env->regs[15] & 1) {
+            env->regs[15] &= ~1U;
+            if (!arm_feature(env, ARM_FEATURE_V8)) {
+                qemu_log_mask(LOG_GUEST_ERROR,
+                              "M profile return from interrupt with misaligned "
+                              "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 = (xpsr & XPSR_EXCP) != 0;
+            if (return_to_handler != will_be_handler) {
+                /*
+                 * Take an INVPC UsageFault on the current stack.
+                 * By this point we will have switched to the security state
+                 * 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] |= R_V7M_CFSR_INVPC_MASK;
+                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;
+            }
+        }
+
+        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, false);
+                env->v7m.sfsr |= R_V7M_SFSR_LSERR_MASK;
+                qemu_log_mask(CPU_LOG_INT,
+                              "...taking SecureFault on existing stackframe: "
+                              "Secure LSPACT set but exception return is "
+                              "not to secure state\n");
+                v7m_exception_taken(cpu, excret, true, false);
+                return;
+            }
+
+            restore_s16_s31 = 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] &= ~R_V7M_FPCCR_LSPACT_MASK;
+            } else {
+                int i;
+                uint32_t fpscr;
+                bool cpacr_pass, nsacr_pass;
+
+                cpacr_pass = v7m_cpacr_pass(env, return_to_secure,
+                                            return_to_priv);
+                nsacr_pass = 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] |= R_V7M_CFSR_NOCP_MASK;
+                    qemu_log_mask(CPU_LOG_INT,
+                                  "...taking UsageFault on existing "
+                                  "stackframe: CPACR.CP10 prevents unstacking "
+                                  "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] |= R_V7M_CFSR_INVPC_MASK;
+                    qemu_log_mask(CPU_LOG_INT,
+                                  "...taking Secure UsageFault on existing "
+                                  "stackframe: NSACR.CP10 prevents unstacking "
+                                  "FP regs\n");
+                    v7m_exception_taken(cpu, excret, true, false);
+                    return;
+                }
+
+                for (i = 0; i < (restore_s16_s31 ? 32 : 16); i += 2) {
+                    uint32_t slo, shi;
+                    uint64_t dn;
+                    uint32_t faddr = frameptr + 0x20 + 4 * i;
+
+                    if (i >= 16) {
+                        faddr += 8; /* Skip the slot for the FPSCR */
+                    }
+
+                    pop_ok = pop_ok &&
+                        v7m_stack_read(cpu, &slo, faddr, mmu_idx) &&
+                        v7m_stack_read(cpu, &shi, faddr + 4, mmu_idx);
+
+                    if (!pop_ok) {
+                        break;
+                    }
+
+                    dn = (uint64_t)shi << 32 | slo;
+                    *aa32_vfp_dreg(env, i / 2) = dn;
+                }
+                pop_ok = 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 = 0; i < (restore_s16_s31 ? 32 : 16); i += 2) {
+                        *aa32_vfp_dreg(env, i / 2) = 0;
+                    }
+                    vfp_set_fpscr(env, 0);
+                }
+            }
+        }
+        env->v7m.control[M_REG_S] = FIELD_DP32(env->v7m.control[M_REG_S],
+                                               V7M_CONTROL, FPCA, !ftype);
+
+        /* Commit to consuming the stack frame */
+        frameptr += 0x20;
+        if (!ftype) {
+            frameptr += 0x48;
+            if (restore_s16_s31) {
+                frameptr += 0x40;
+            }
+        }
+        /*
+         * Undo stack alignment (the SPREALIGN bit indicates that the original
+         * 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. (Adding 4
+         * would work too but a logical OR is how the pseudocode specifies it.)
+         */
+        if (xpsr & XPSR_SPREALIGN) {
+            frameptr |= 4;
+        }
+        *frame_sp_p = frameptr;
+    }
+
+    xpsr_mask = ~(XPSR_SPREALIGN | XPSR_SFPA);
+    if (!arm_feature(env, ARM_FEATURE_THUMB_DSP)) {
+        xpsr_mask &= ~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 = xpsr & XPSR_SFPA;
+
+        env->v7m.control[M_REG_S] = 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 != 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] |= R_V7M_CFSR_INVPC_MASK;
+        ignore_stackfaults = 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 = &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 = !arm_v7m_is_handler_mode(env);
+        spsel = env->v7m.control[M_REG_S] & R_V7M_CONTROL_SPSEL_MASK;
+
+        frame_sp_p = get_v7m_sp_ptr(env, true, threadmode, spsel);
+        frameptr = *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 = arm_v7m_mmu_idx_for_secstate(env, true);
+        oi = make_memop_idx(MO_LE, arm_to_core_mmu_idx(mmu_idx));
+        newpc = helper_le_ldul_mmu(env, frameptr, oi, 0);
+        newpsr = helper_le_ldul_mmu(env, frameptr + 4, oi, 0);
+
+        /* Consistency checks on new IPSR */
+        newpsr_exc = newpsr & XPSR_EXCP;
+        if (!((env->v7m.exception == 0 && newpsr_exc == 0) ||
+              (env->v7m.exception == 1 && newpsr_exc != 0))) {
+            /* Pend the fault and tell our caller to take it */
+            env->v7m.cfsr[env->v7m.secure] |= 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 = frameptr + 8;
+    }
+
+    /* This invalidates frame_sp_p */
+    switch_v7m_security_state(env, true);
+    env->v7m.exception = newpsr_exc;
+    env->v7m.control[M_REG_S] &= ~R_V7M_CONTROL_SFPA_MASK;
+    if (newpsr & XPSR_SFPA) {
+        env->v7m.control[M_REG_S] |= R_V7M_CONTROL_SFPA_MASK;
+    }
+    xpsr_write(env, 0, XPSR_IT);
+    env->thumb = newpc & 1;
+    env->regs[15] = 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 success,
+     * or false on failure (in which case we will have pended the appropriate
+     * 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 = CPU(cpu);
+    CPUARMState *env = &cpu->env;
+    V8M_SAttributes sattrs = {};
+    MemTxAttrs attrs = {};
+    ARMMMUFaultInfo fi = {};
+    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 |= 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] |= R_V7M_CFSR_IACCVIOL_MASK;
+        armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_MEM, env->v7m.secure);
+        qemu_log_mask(CPU_LOG_INT, "...really MemManage with CFSR.IACCVIOL\n");
+        return false;
+    }
+    *insn = address_space_lduw_le(arm_addressspace(cs, attrs), physaddr,
+                                 attrs, &txres);
+    if (txres != MEMTX_OK) {
+        env->v7m.cfsr[M_REG_NS] |= 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 = &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 = 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 != 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 != 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" PRIx32
+                  ", executing it\n", env->regs[15]);
+    env->regs[14] &= ~1;
+    env->v7m.control[M_REG_S] &= ~R_V7M_CONTROL_SFPA_MASK;
+    switch_v7m_security_state(env, true);
+    xpsr_write(env, 0, XPSR_IT);
+    env->regs[15] += 4;
+    return true;
+
+gen_invep:
+    env->v7m.sfsr |= 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 = ARM_CPU(cs);
+    CPUARMState *env = &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.secure);
+        env->v7m.cfsr[env->v7m.secure] |= 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 == 3) {
+            target_secstate = M_REG_S;
+        } else {
+            target_secstate = env->v7m.secure;
+        }
+        armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_USAGE, target_secstate);
+        env->v7m.cfsr[target_secstate] |= R_V7M_CFSR_NOCP_MASK;
+        break;
+    }
+    case EXCP_INVSTATE:
+        armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_USAGE, env->v7m.secure);
+        env->v7m.cfsr[env->v7m.secure] |= R_V7M_CFSR_INVSTATE_MASK;
+        break;
+    case EXCP_STKOF:
+        armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_USAGE, env->v7m.secure);
+        env->v7m.cfsr[env->v7m.secure] |= R_V7M_CFSR_STKOF_MASK;
+        break;
+    case EXCP_LSERR:
+        armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_SECURE, false);
+        env->v7m.sfsr |= R_V7M_SFSR_LSERR_MASK;
+        break;
+    case EXCP_UNALIGNED:
+        armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_USAGE, env->v7m.secure);
+        env->v7m.cfsr[env->v7m.secure] |= 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.secure);
+        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 address
+             * 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 |= R_V7M_SFSR_INVTRAN_MASK;
+                    qemu_log_mask(CPU_LOG_INT,
+                                  "...really SecureFault with SFSR.INVTRAN\n");
+                } else {
+                    env->v7m.sfsr |= 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 |= 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] |= 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] |=
+                    (R_V7M_CFSR_PRECISERR_MASK | R_V7M_CFSR_BFARVALID_MASK);
+                env->v7m.bfar = 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] |= R_V7M_CFSR_IACCVIOL_MASK;
+                qemu_log_mask(CPU_LOG_INT, "...with CFSR.IACCVIOL\n");
+                break;
+            case EXCP_DATA_ABORT:
+                env->v7m.cfsr[env->v7m.secure] |=
+                    (R_V7M_CFSR_DACCVIOL_MASK | R_V7M_CFSR_MMARVALID_MASK);
+                env->v7m.mmfar[env->v7m.secure] = env->exception.vaddress;
+                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 = arm_lduw_code(env, env->regs[15], arm_sctlr_b(env)) & 0xff;
+            if (nr == 0xab) {
+                env->regs[15] += 2;
+                qemu_log_mask(CPU_LOG_INT,
+                              "...handling as semihosting call 0x%x\n",
+                              env->regs[0]);
+                env->regs[0] = 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] >= 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 = 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 |= R_V7M_EXCRET_S_MASK;
+        }
+        if (!(env->v7m.control[M_REG_S] & R_V7M_CONTROL_FPCA_MASK)) {
+            lr |= R_V7M_EXCRET_FTYPE_MASK;
+        }
+    } else {
+        lr = 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 |= R_V7M_EXCRET_SPSEL_MASK;
+        }
+    }
+    if (!arm_v7m_is_handler_mode(env)) {
+        lr |= R_V7M_EXCRET_MODE_MASK;
+    }
+
+    ignore_stackfaults = v7m_push_stack(cpu);
+    v7m_exception_taken(cpu, lr, false, ignore_stackfaults);
+}
+
 #endif /* CONFIG_USER_ONLY */
-- 
2.20.1



^ permalink raw reply related	[flat|nested] 51+ messages in thread

* [Qemu-devel] [PATCH v2 13/23] target/arm: Make the v7-M Security State routines
  2019-06-15 15:43 [Qemu-devel] [PATCH v2 00/23] Support disabling TCG on ARM Philippe Mathieu-Daudé
                   ` (11 preceding siblings ...)
  2019-06-15 15:43 ` [Qemu-devel] [PATCH v2 12/23] target/arm: Move v7m exception handling routines to v7m_helper Philippe Mathieu-Daudé
@ 2019-06-15 15:43 ` Philippe Mathieu-Daudé
  2019-06-17 14:11   ` [Qemu-devel] [Qemu-arm] " Alex Bennée
  2019-06-15 15:43 ` [Qemu-devel] [PATCH v2 14/23] target/arm: Move the DC ZVA helper into op_helper Philippe Mathieu-Daudé
                   ` (9 subsequent siblings)
  22 siblings, 1 reply; 51+ messages in thread
From: Philippe Mathieu-Daudé @ 2019-06-15 15:43 UTC (permalink / raw)
  To: qemu-devel; +Cc: Peter Maydell, qemu-arm, Philippe Mathieu-Daudé

The Security State helpers are now only called within v7m_helper.c.
Remove them from "internals.h".

Signed-off-by: Philippe Mathieu-Daudé <philmd@redhat.com>
---
 target/arm/internals.h  |  8 --------
 target/arm/v7m_helper.c | 10 +++++-----
 2 files changed, 5 insertions(+), 13 deletions(-)

diff --git a/target/arm/internals.h b/target/arm/internals.h
index 1d15af3f8b..fe9e4665e2 100644
--- a/target/arm/internals.h
+++ b/target/arm/internals.h
@@ -1043,12 +1043,4 @@ bool pmsav8_mpu_lookup(CPUARMState *env, uint32_t address,
                        int *prot, bool *is_subpage,
                        ARMMMUFaultInfo *fi, uint32_t *mregion);
 
-void write_v7m_control_spsel_for_secstate(CPUARMState *env,
-                                          bool new_spsel,
-                                          bool secstate);
-
-void write_v7m_control_spsel(CPUARMState *env, bool new_spsel);
-
-void switch_v7m_security_state(CPUARMState *env, bool new_secstate);
-
 #endif
diff --git a/target/arm/v7m_helper.c b/target/arm/v7m_helper.c
index b50bb98e06..aa6a08e326 100644
--- a/target/arm/v7m_helper.c
+++ b/target/arm/v7m_helper.c
@@ -94,9 +94,9 @@ uint32_t HELPER(v7m_tt)(CPUARMState *env, uint32_t addr, uint32_t op)
  * stack pointers if it is done for the CONTROL register for the current
  * security state.
  */
-void write_v7m_control_spsel_for_secstate(CPUARMState *env,
-                                          bool new_spsel,
-                                          bool secstate)
+static void write_v7m_control_spsel_for_secstate(CPUARMState *env,
+                                                 bool new_spsel,
+                                                 bool secstate)
 {
     bool old_is_psp = v7m_using_psp(env);
 
@@ -121,13 +121,13 @@ void write_v7m_control_spsel_for_secstate(CPUARMState *env,
  * Write to v7M CONTROL.SPSEL bit. This may change the current
  * stack pointer between Main and Process stack pointers.
  */
-void write_v7m_control_spsel(CPUARMState *env, bool new_spsel)
+static void write_v7m_control_spsel(CPUARMState *env, bool new_spsel)
 {
     write_v7m_control_spsel_for_secstate(env, new_spsel, env->v7m.secure);
 }
 
 /* Switch M profile security state between NS and S */
-void switch_v7m_security_state(CPUARMState *env, bool new_secstate)
+static void switch_v7m_security_state(CPUARMState *env, bool new_secstate)
 {
     uint32_t new_ss_msp, new_ss_psp;
 
-- 
2.20.1



^ permalink raw reply related	[flat|nested] 51+ messages in thread

* [Qemu-devel] [PATCH v2 14/23] target/arm: Move the DC ZVA helper into op_helper
  2019-06-15 15:43 [Qemu-devel] [PATCH v2 00/23] Support disabling TCG on ARM Philippe Mathieu-Daudé
                   ` (12 preceding siblings ...)
  2019-06-15 15:43 ` [Qemu-devel] [PATCH v2 13/23] target/arm: Make the v7-M Security State routines Philippe Mathieu-Daudé
@ 2019-06-15 15:43 ` Philippe Mathieu-Daudé
  2019-06-17 14:12   ` [Qemu-devel] [Qemu-arm] " Alex Bennée
  2019-06-15 15:43 ` [Qemu-devel] [PATCH v2 15/23] target/arm: Make ARM TLB filling routine static Philippe Mathieu-Daudé
                   ` (8 subsequent siblings)
  22 siblings, 1 reply; 51+ messages in thread
From: Philippe Mathieu-Daudé @ 2019-06-15 15:43 UTC (permalink / raw)
  To: qemu-devel
  Cc: Peter Maydell, qemu-arm, Philippe Mathieu-Daudé,
	Samuel Ortiz, Robert Bradford

From: Samuel Ortiz <sameo@linux.intel.com>

Those helpers are a software implementation of the ARM v8 memory zeroing
op code. They should be moved to the op helper file, which is going to
eventually be built only when TCG is enabled.

Signed-off-by: Samuel Ortiz <sameo@linux.intel.com>
Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com>
Reviewed-by: Robert Bradford <robert.bradford@intel.com>
[PMD: Rebased]
Signed-off-by: Philippe Mathieu-Daudé <philmd@redhat.com>
---
 target/arm/helper.c    | 92 -----------------------------------------
 target/arm/op_helper.c | 93 ++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 93 insertions(+), 92 deletions(-)

diff --git a/target/arm/helper.c b/target/arm/helper.c
index 24d88eef17..673ada1e86 100644
--- a/target/arm/helper.c
+++ b/target/arm/helper.c
@@ -10674,98 +10674,6 @@ bool arm_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
 #endif
 }
 
-void HELPER(dc_zva)(CPUARMState *env, uint64_t vaddr_in)
-{
-    /*
-     * Implement DC ZVA, which zeroes a fixed-length block of memory.
-     * Note that we do not implement the (architecturally mandated)
-     * alignment fault for attempts to use this on Device memory
-     * (which matches the usual QEMU behaviour of not implementing either
-     * alignment faults or any memory attribute handling).
-     */
-
-    ARMCPU *cpu = env_archcpu(env);
-    uint64_t blocklen = 4 << cpu->dcz_blocksize;
-    uint64_t vaddr = vaddr_in & ~(blocklen - 1);
-
-#ifndef CONFIG_USER_ONLY
-    {
-        /*
-         * Slightly awkwardly, QEMU's TARGET_PAGE_SIZE may be less than
-         * the block size so we might have to do more than one TLB lookup.
-         * We know that in fact for any v8 CPU the page size is at least 4K
-         * and the block size must be 2K or less, but TARGET_PAGE_SIZE is only
-         * 1K as an artefact of legacy v5 subpage support being present in the
-         * same QEMU executable. So in practice the hostaddr[] array has
-         * two entries, given the current setting of TARGET_PAGE_BITS_MIN.
-         */
-        int maxidx = DIV_ROUND_UP(blocklen, TARGET_PAGE_SIZE);
-        void *hostaddr[DIV_ROUND_UP(2 * KiB, 1 << TARGET_PAGE_BITS_MIN)];
-        int try, i;
-        unsigned mmu_idx = cpu_mmu_index(env, false);
-        TCGMemOpIdx oi = make_memop_idx(MO_UB, mmu_idx);
-
-        assert(maxidx <= ARRAY_SIZE(hostaddr));
-
-        for (try = 0; try < 2; try++) {
-
-            for (i = 0; i < maxidx; i++) {
-                hostaddr[i] = tlb_vaddr_to_host(env,
-                                                vaddr + TARGET_PAGE_SIZE * i,
-                                                1, mmu_idx);
-                if (!hostaddr[i]) {
-                    break;
-                }
-            }
-            if (i == maxidx) {
-                /*
-                 * If it's all in the TLB it's fair game for just writing to;
-                 * we know we don't need to update dirty status, etc.
-                 */
-                for (i = 0; i < maxidx - 1; i++) {
-                    memset(hostaddr[i], 0, TARGET_PAGE_SIZE);
-                }
-                memset(hostaddr[i], 0, blocklen - (i * TARGET_PAGE_SIZE));
-                return;
-            }
-            /*
-             * OK, try a store and see if we can populate the tlb. This
-             * might cause an exception if the memory isn't writable,
-             * in which case we will longjmp out of here. We must for
-             * this purpose use the actual register value passed to us
-             * so that we get the fault address right.
-             */
-            helper_ret_stb_mmu(env, vaddr_in, 0, oi, GETPC());
-            /* Now we can populate the other TLB entries, if any */
-            for (i = 0; i < maxidx; i++) {
-                uint64_t va = vaddr + TARGET_PAGE_SIZE * i;
-                if (va != (vaddr_in & TARGET_PAGE_MASK)) {
-                    helper_ret_stb_mmu(env, va, 0, oi, GETPC());
-                }
-            }
-        }
-
-        /*
-         * Slow path (probably attempt to do this to an I/O device or
-         * similar, or clearing of a block of code we have translations
-         * cached for). Just do a series of byte writes as the architecture
-         * demands. It's not worth trying to use a cpu_physical_memory_map(),
-         * memset(), unmap() sequence here because:
-         *  + we'd need to account for the blocksize being larger than a page
-         *  + the direct-RAM access case is almost always going to be dealt
-         *    with in the fastpath code above, so there's no speed benefit
-         *  + we would have to deal with the map returning NULL because the
-         *    bounce buffer was in use
-         */
-        for (i = 0; i < blocklen; i++) {
-            helper_ret_stb_mmu(env, vaddr + i, 0, oi, GETPC());
-        }
-    }
-#else
-    memset(g2h(vaddr), 0, blocklen);
-#endif
-}
-
 /* Note that signed overflow is undefined in C.  The following routines are
    careful to use unsigned types where modulo arithmetic is required.
    Failure to do so _will_ break on newer gcc.  */
diff --git a/target/arm/op_helper.c b/target/arm/op_helper.c
index db4254a67b..29b56039e5 100644
--- a/target/arm/op_helper.c
+++ b/target/arm/op_helper.c
@@ -17,6 +17,7 @@
  * License along with this library; if not, see <http://www.gnu.org/licenses/>.
  */
 #include "qemu/osdep.h"
+#include "qemu/units.h"
 #include "qemu/log.h"
 #include "qemu/main-loop.h"
 #include "cpu.h"
@@ -1316,3 +1317,95 @@ uint32_t HELPER(ror_cc)(CPUARMState *env, uint32_t x, uint32_t i)
         return ((uint32_t)x >> shift) | (x << (32 - shift));
     }
 }
+
+void HELPER(dc_zva)(CPUARMState *env, uint64_t vaddr_in)
+{
+    /*
+     * Implement DC ZVA, which zeroes a fixed-length block of memory.
+     * Note that we do not implement the (architecturally mandated)
+     * alignment fault for attempts to use this on Device memory
+     * (which matches the usual QEMU behaviour of not implementing either
+     * alignment faults or any memory attribute handling).
+     */
+
+    ARMCPU *cpu = env_archcpu(env);
+    uint64_t blocklen = 4 << cpu->dcz_blocksize;
+    uint64_t vaddr = vaddr_in & ~(blocklen - 1);
+
+#ifndef CONFIG_USER_ONLY
+    {
+        /*
+         * Slightly awkwardly, QEMU's TARGET_PAGE_SIZE may be less than
+         * the block size so we might have to do more than one TLB lookup.
+         * We know that in fact for any v8 CPU the page size is at least 4K
+         * and the block size must be 2K or less, but TARGET_PAGE_SIZE is only
+         * 1K as an artefact of legacy v5 subpage support being present in the
+         * same QEMU executable. So in practice the hostaddr[] array has
+         * two entries, given the current setting of TARGET_PAGE_BITS_MIN.
+         */
+        int maxidx = DIV_ROUND_UP(blocklen, TARGET_PAGE_SIZE);
+        void *hostaddr[DIV_ROUND_UP(2 * KiB, 1 << TARGET_PAGE_BITS_MIN)];
+        int try, i;
+        unsigned mmu_idx = cpu_mmu_index(env, false);
+        TCGMemOpIdx oi = make_memop_idx(MO_UB, mmu_idx);
+
+        assert(maxidx <= ARRAY_SIZE(hostaddr));
+
+        for (try = 0; try < 2; try++) {
+
+            for (i = 0; i < maxidx; i++) {
+                hostaddr[i] = tlb_vaddr_to_host(env,
+                                                vaddr + TARGET_PAGE_SIZE * i,
+                                                1, mmu_idx);
+                if (!hostaddr[i]) {
+                    break;
+                }
+            }
+            if (i == maxidx) {
+                /*
+                 * If it's all in the TLB it's fair game for just writing to;
+                 * we know we don't need to update dirty status, etc.
+                 */
+                for (i = 0; i < maxidx - 1; i++) {
+                    memset(hostaddr[i], 0, TARGET_PAGE_SIZE);
+                }
+                memset(hostaddr[i], 0, blocklen - (i * TARGET_PAGE_SIZE));
+                return;
+            }
+            /*
+             * OK, try a store and see if we can populate the tlb. This
+             * might cause an exception if the memory isn't writable,
+             * in which case we will longjmp out of here. We must for
+             * this purpose use the actual register value passed to us
+             * so that we get the fault address right.
+             */
+            helper_ret_stb_mmu(env, vaddr_in, 0, oi, GETPC());
+            /* Now we can populate the other TLB entries, if any */
+            for (i = 0; i < maxidx; i++) {
+                uint64_t va = vaddr + TARGET_PAGE_SIZE * i;
+                if (va != (vaddr_in & TARGET_PAGE_MASK)) {
+                    helper_ret_stb_mmu(env, va, 0, oi, GETPC());
+                }
+            }
+        }
+
+        /*
+         * Slow path (probably attempt to do this to an I/O device or
+         * similar, or clearing of a block of code we have translations
+         * cached for). Just do a series of byte writes as the architecture
+         * demands. It's not worth trying to use a cpu_physical_memory_map(),
+         * memset(), unmap() sequence here because:
+         *  + we'd need to account for the blocksize being larger than a page
+         *  + the direct-RAM access case is almost always going to be dealt
+         *    with in the fastpath code above, so there's no speed benefit
+         *  + we would have to deal with the map returning NULL because the
+         *    bounce buffer was in use
+         */
+        for (i = 0; i < blocklen; i++) {
+            helper_ret_stb_mmu(env, vaddr + i, 0, oi, GETPC());
+        }
+    }
+#else
+    memset(g2h(vaddr), 0, blocklen);
+#endif
+}
-- 
2.20.1



^ permalink raw reply related	[flat|nested] 51+ messages in thread

* [Qemu-devel] [PATCH v2 15/23] target/arm: Make ARM TLB filling routine static
  2019-06-15 15:43 [Qemu-devel] [PATCH v2 00/23] Support disabling TCG on ARM Philippe Mathieu-Daudé
                   ` (13 preceding siblings ...)
  2019-06-15 15:43 ` [Qemu-devel] [PATCH v2 14/23] target/arm: Move the DC ZVA helper into op_helper Philippe Mathieu-Daudé
@ 2019-06-15 15:43 ` Philippe Mathieu-Daudé
  2019-06-17 14:16   ` [Qemu-devel] [Qemu-arm] " Alex Bennée
  2019-06-15 15:43 ` [Qemu-devel] [PATCH v2 16/23] target/arm: Make arm_deliver_fault() static Philippe Mathieu-Daudé
                   ` (7 subsequent siblings)
  22 siblings, 1 reply; 51+ messages in thread
From: Philippe Mathieu-Daudé @ 2019-06-15 15:43 UTC (permalink / raw)
  To: qemu-devel
  Cc: Peter Maydell, qemu-arm, Philippe Mathieu-Daudé, Samuel Ortiz

From: Samuel Ortiz <sameo@linux.intel.com>

It's only used in op_helper.c, it does not need to be exported and
moreover it should only be build when TCG is enabled.

Signed-off-by: Samuel Ortiz <sameo@linux.intel.com>
[PMD: Rebased]
Signed-off-by: Philippe Mathieu-Daudé <philmd@redhat.com>
---
 target/arm/helper.c    | 53 ---------------------------------------
 target/arm/internals.h |  2 ++
 target/arm/op_helper.c | 56 ++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 58 insertions(+), 53 deletions(-)

diff --git a/target/arm/helper.c b/target/arm/helper.c
index 673ada1e86..a4af02c984 100644
--- a/target/arm/helper.c
+++ b/target/arm/helper.c
@@ -10621,59 +10621,6 @@ hwaddr arm_cpu_get_phys_page_attrs_debug(CPUState *cs, vaddr addr,
 
 #endif
 
-bool arm_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
-                      MMUAccessType access_type, int mmu_idx,
-                      bool probe, uintptr_t retaddr)
-{
-    ARMCPU *cpu = ARM_CPU(cs);
-
-#ifdef CONFIG_USER_ONLY
-    cpu->env.exception.vaddress = address;
-    if (access_type == MMU_INST_FETCH) {
-        cs->exception_index = EXCP_PREFETCH_ABORT;
-    } else {
-        cs->exception_index = EXCP_DATA_ABORT;
-    }
-    cpu_loop_exit_restore(cs, retaddr);
-#else
-    hwaddr phys_addr;
-    target_ulong page_size;
-    int prot, ret;
-    MemTxAttrs attrs = {};
-    ARMMMUFaultInfo fi = {};
-
-    /*
-     * Walk the page table and (if the mapping exists) add the page
-     * to the TLB.  On success, return true.  Otherwise, if probing,
-     * return false.  Otherwise populate fsr with ARM DFSR/IFSR fault
-     * register format, and signal the fault.
-     */
-    ret = get_phys_addr(&cpu->env, address, access_type,
-                        core_to_arm_mmu_idx(&cpu->env, mmu_idx),
-                        &phys_addr, &attrs, &prot, &page_size, &fi, NULL);
-    if (likely(!ret)) {
-        /*
-         * Map a single [sub]page. Regions smaller than our declared
-         * target page size are handled specially, so for those we
-         * pass in the exact addresses.
-         */
-        if (page_size >= TARGET_PAGE_SIZE) {
-            phys_addr &= TARGET_PAGE_MASK;
-            address &= TARGET_PAGE_MASK;
-        }
-        tlb_set_page_with_attrs(cs, address, phys_addr, attrs,
-                                prot, mmu_idx, page_size);
-        return true;
-    } else if (probe) {
-        return false;
-    } else {
-        /* now we have a real cpu fault */
-        cpu_restore_state(cs, retaddr, true);
-        arm_deliver_fault(cpu, address, access_type, mmu_idx, &fi);
-    }
-#endif
-}
-
 /* Note that signed overflow is undefined in C.  The following routines are
    careful to use unsigned types where modulo arithmetic is required.
    Failure to do so _will_ break on newer gcc.  */
diff --git a/target/arm/internals.h b/target/arm/internals.h
index fe9e4665e2..37ca493635 100644
--- a/target/arm/internals.h
+++ b/target/arm/internals.h
@@ -761,9 +761,11 @@ static inline bool arm_extabort_type(MemTxResult result)
     return result != MEMTX_DECODE_ERROR;
 }
 
+#ifdef CONFIG_TCG
 bool arm_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
                       MMUAccessType access_type, int mmu_idx,
                       bool probe, uintptr_t retaddr);
+#endif
 
 void arm_deliver_fault(ARMCPU *cpu, vaddr addr, MMUAccessType access_type,
                        int mmu_idx, ARMMMUFaultInfo *fi) QEMU_NORETURN;
diff --git a/target/arm/op_helper.c b/target/arm/op_helper.c
index 29b56039e5..e43c99ebf0 100644
--- a/target/arm/op_helper.c
+++ b/target/arm/op_helper.c
@@ -179,6 +179,62 @@ void arm_deliver_fault(ARMCPU *cpu, vaddr addr, MMUAccessType access_type,
     env->exception.fsr = fsr;
     raise_exception(env, exc, syn, target_el);
 }
+#endif
+
+bool arm_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
+                      MMUAccessType access_type, int mmu_idx,
+                      bool probe, uintptr_t retaddr)
+{
+    ARMCPU *cpu = ARM_CPU(cs);
+
+#ifdef CONFIG_USER_ONLY
+    cpu->env.exception.vaddress = address;
+    if (access_type == MMU_INST_FETCH) {
+        cs->exception_index = EXCP_PREFETCH_ABORT;
+    } else {
+        cs->exception_index = EXCP_DATA_ABORT;
+    }
+    cpu_loop_exit_restore(cs, retaddr);
+#else
+    hwaddr phys_addr;
+    target_ulong page_size;
+    int prot, ret;
+    MemTxAttrs attrs = {};
+    ARMMMUFaultInfo fi = {};
+
+    /*
+     * Walk the page table and (if the mapping exists) add the page
+     * to the TLB.  On success, return true.  Otherwise, if probing,
+     * return false.  Otherwise populate fsr with ARM DFSR/IFSR fault
+     * register format, and signal the fault.
+     */
+    ret = get_phys_addr(&cpu->env, address, access_type,
+                        core_to_arm_mmu_idx(&cpu->env, mmu_idx),
+                        &phys_addr, &attrs, &prot, &page_size, &fi, NULL);
+    if (likely(!ret)) {
+        /*
+         * Map a single [sub]page. Regions smaller than our declared
+         * target page size are handled specially, so for those we
+         * pass in the exact addresses.
+         */
+        if (page_size >= TARGET_PAGE_SIZE) {
+            phys_addr &= TARGET_PAGE_MASK;
+            address &= TARGET_PAGE_MASK;
+        }
+        tlb_set_page_with_attrs(cs, address, phys_addr, attrs,
+                                prot, mmu_idx, page_size);
+        return true;
+    } else if (probe) {
+        return false;
+    } else {
+        /* now we have a real cpu fault */
+        cpu_restore_state(cs, retaddr, true);
+        arm_deliver_fault(cpu, address, access_type, mmu_idx, &fi);
+    }
+#endif
+}
+
+#if !defined(CONFIG_USER_ONLY)
 
 /* Raise a data fault alignment exception for the specified virtual address */
 void arm_cpu_do_unaligned_access(CPUState *cs, vaddr vaddr,
-- 
2.20.1



^ permalink raw reply related	[flat|nested] 51+ messages in thread

* [Qemu-devel] [PATCH v2 16/23] target/arm: Make arm_deliver_fault() static
  2019-06-15 15:43 [Qemu-devel] [PATCH v2 00/23] Support disabling TCG on ARM Philippe Mathieu-Daudé
                   ` (14 preceding siblings ...)
  2019-06-15 15:43 ` [Qemu-devel] [PATCH v2 15/23] target/arm: Make ARM TLB filling routine static Philippe Mathieu-Daudé
@ 2019-06-15 15:43 ` Philippe Mathieu-Daudé
  2019-06-17 14:19   ` [Qemu-devel] [Qemu-arm] " Alex Bennée
  2019-06-15 15:43 ` [Qemu-devel] [PATCH v2 17/23] target/arm: Fix coding style issues Philippe Mathieu-Daudé
                   ` (6 subsequent siblings)
  22 siblings, 1 reply; 51+ messages in thread
From: Philippe Mathieu-Daudé @ 2019-06-15 15:43 UTC (permalink / raw)
  To: qemu-devel; +Cc: Peter Maydell, qemu-arm, Philippe Mathieu-Daudé

This function is now only called within op_helper.c.

Signed-off-by: Philippe Mathieu-Daudé <philmd@redhat.com>
---
 target/arm/internals.h | 3 ---
 target/arm/op_helper.c | 5 +++--
 2 files changed, 3 insertions(+), 5 deletions(-)

diff --git a/target/arm/internals.h b/target/arm/internals.h
index 37ca493635..06e676bf62 100644
--- a/target/arm/internals.h
+++ b/target/arm/internals.h
@@ -767,9 +767,6 @@ bool arm_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
                       bool probe, uintptr_t retaddr);
 #endif
 
-void arm_deliver_fault(ARMCPU *cpu, vaddr addr, MMUAccessType access_type,
-                       int mmu_idx, ARMMMUFaultInfo *fi) QEMU_NORETURN;
-
 /* Return true if the stage 1 translation regime is using LPAE format page
  * tables */
 bool arm_s1_regime_using_lpae_format(CPUARMState *env, ARMMMUIdx mmu_idx);
diff --git a/target/arm/op_helper.c b/target/arm/op_helper.c
index e43c99ebf0..63bce32810 100644
--- a/target/arm/op_helper.c
+++ b/target/arm/op_helper.c
@@ -127,8 +127,9 @@ static inline uint32_t merge_syn_data_abort(uint32_t template_syn,
     return syn;
 }
 
-void arm_deliver_fault(ARMCPU *cpu, vaddr addr, MMUAccessType access_type,
-                       int mmu_idx, ARMMMUFaultInfo *fi)
+static void QEMU_NORETURN arm_deliver_fault(ARMCPU *cpu, vaddr addr,
+                                            MMUAccessType access_type,
+                                            int mmu_idx, ARMMMUFaultInfo *fi)
 {
     CPUARMState *env = &cpu->env;
     int target_el;
-- 
2.20.1



^ permalink raw reply related	[flat|nested] 51+ messages in thread

* [Qemu-devel] [PATCH v2 17/23] target/arm: Fix coding style issues
  2019-06-15 15:43 [Qemu-devel] [PATCH v2 00/23] Support disabling TCG on ARM Philippe Mathieu-Daudé
                   ` (15 preceding siblings ...)
  2019-06-15 15:43 ` [Qemu-devel] [PATCH v2 16/23] target/arm: Make arm_deliver_fault() static Philippe Mathieu-Daudé
@ 2019-06-15 15:43 ` Philippe Mathieu-Daudé
  2019-06-17 14:20   ` [Qemu-devel] [Qemu-arm] " Alex Bennée
  2019-06-15 15:43 ` [Qemu-devel] [PATCH v2 18/23] target/arm: Move CPU state dumping routines to helper.c Philippe Mathieu-Daudé
                   ` (5 subsequent siblings)
  22 siblings, 1 reply; 51+ messages in thread
From: Philippe Mathieu-Daudé @ 2019-06-15 15:43 UTC (permalink / raw)
  To: qemu-devel; +Cc: Peter Maydell, qemu-arm, Philippe Mathieu-Daudé

Since we'll move this code around, fix its style first.

Signed-off-by: Philippe Mathieu-Daudé <philmd@redhat.com>
---
 target/arm/translate.c | 11 ++++++-----
 1 file changed, 6 insertions(+), 5 deletions(-)

diff --git a/target/arm/translate.c b/target/arm/translate.c
index c274c8b460..d0ab3e27e6 100644
--- a/target/arm/translate.c
+++ b/target/arm/translate.c
@@ -9179,7 +9179,7 @@ static void disas_arm_insn(DisasContext *s, unsigned int insn)
                 loaded_base = 0;
                 loaded_var = NULL;
                 n = 0;
-                for(i=0;i<16;i++) {
+                for (i = 0; i < 16; i++) {
                     if (insn & (1 << i))
                         n++;
                 }
@@ -9202,7 +9202,7 @@ static void disas_arm_insn(DisasContext *s, unsigned int insn)
                     }
                 }
                 j = 0;
-                for(i=0;i<16;i++) {
+                for (i = 0; i < 16; i++) {
                     if (insn & (1 << i)) {
                         if (is_load) {
                             /* load */
@@ -12427,12 +12427,13 @@ void arm_cpu_dump_state(CPUState *cs, FILE *f, int flags)
         return;
     }
 
-    for(i=0;i<16;i++) {
+    for (i = 0; i < 16; i++) {
         qemu_fprintf(f, "R%02d=%08x", i, env->regs[i]);
-        if ((i % 4) == 3)
+        if ((i % 4) == 3) {
             qemu_fprintf(f, "\n");
-        else
+        } else {
             qemu_fprintf(f, " ");
+        }
     }
 
     if (arm_feature(env, ARM_FEATURE_M)) {
-- 
2.20.1



^ permalink raw reply related	[flat|nested] 51+ messages in thread

* [Qemu-devel] [PATCH v2 18/23] target/arm: Move CPU state dumping routines to helper.c
  2019-06-15 15:43 [Qemu-devel] [PATCH v2 00/23] Support disabling TCG on ARM Philippe Mathieu-Daudé
                   ` (16 preceding siblings ...)
  2019-06-15 15:43 ` [Qemu-devel] [PATCH v2 17/23] target/arm: Fix coding style issues Philippe Mathieu-Daudé
@ 2019-06-15 15:43 ` Philippe Mathieu-Daudé
  2019-06-17 14:41   ` [Qemu-devel] [Qemu-arm] " Alex Bennée
  2019-06-15 15:43 ` [Qemu-devel] [PATCH v2 19/23] target/arm: Move watchpoints APIs " Philippe Mathieu-Daudé
                   ` (4 subsequent siblings)
  22 siblings, 1 reply; 51+ messages in thread
From: Philippe Mathieu-Daudé @ 2019-06-15 15:43 UTC (permalink / raw)
  To: qemu-devel
  Cc: Peter Maydell, qemu-arm, Philippe Mathieu-Daudé,
	Samuel Ortiz, Robert Bradford

From: Samuel Ortiz <sameo@linux.intel.com>

They're not TCG specific and should be living the generic helper file
instead.

Signed-off-by: Samuel Ortiz <sameo@linux.intel.com>
Reviewed-by: Robert Bradford <robert.bradford@intel.com>
[PMD: Rebased]
Signed-off-by: Philippe Mathieu-Daudé <philmd@redhat.com>
---
 target/arm/helper.c        | 214 +++++++++++++++++++++++++++++++++++++
 target/arm/internals.h     |   8 ++
 target/arm/translate-a64.c | 127 ----------------------
 target/arm/translate.c     |  87 ---------------
 target/arm/translate.h     |   5 -
 5 files changed, 222 insertions(+), 219 deletions(-)

diff --git a/target/arm/helper.c b/target/arm/helper.c
index a4af02c984..8c32b2bc0d 100644
--- a/target/arm/helper.c
+++ b/target/arm/helper.c
@@ -11293,4 +11293,218 @@ void aarch64_sve_change_el(CPUARMState *env, int old_el,
         aarch64_sve_narrow_vq(env, new_len + 1);
     }
 }
+
+void aarch64_cpu_dump_state(CPUState *cs, FILE *f, int flags)
+{
+    ARMCPU *cpu = ARM_CPU(cs);
+    CPUARMState *env = &cpu->env;
+    uint32_t psr = pstate_read(env);
+    int i;
+    int el = arm_current_el(env);
+    const char *ns_status;
+
+    qemu_fprintf(f, " PC=%016" PRIx64 " ", env->pc);
+    for (i = 0; i < 32; i++) {
+        if (i == 31) {
+            qemu_fprintf(f, " SP=%016" PRIx64 "\n", env->xregs[i]);
+        } else {
+            qemu_fprintf(f, "X%02d=%016" PRIx64 "%s", i, env->xregs[i],
+                         (i + 2) % 3 ? " " : "\n");
+        }
+    }
+
+    if (arm_feature(env, ARM_FEATURE_EL3) && el != 3) {
+        ns_status = env->cp15.scr_el3 & SCR_NS ? "NS " : "S ";
+    } else {
+        ns_status = "";
+    }
+    qemu_fprintf(f, "PSTATE=%08x %c%c%c%c %sEL%d%c",
+                 psr,
+                 psr & PSTATE_N ? 'N' : '-',
+                 psr & PSTATE_Z ? 'Z' : '-',
+                 psr & PSTATE_C ? 'C' : '-',
+                 psr & PSTATE_V ? 'V' : '-',
+                 ns_status,
+                 el,
+                 psr & PSTATE_SP ? 'h' : 't');
+
+    if (cpu_isar_feature(aa64_bti, cpu)) {
+        qemu_fprintf(f, "  BTYPE=%d", (psr & PSTATE_BTYPE) >> 10);
+    }
+    if (!(flags & CPU_DUMP_FPU)) {
+        qemu_fprintf(f, "\n");
+        return;
+    }
+    if (fp_exception_el(env, el) != 0) {
+        qemu_fprintf(f, "    FPU disabled\n");
+        return;
+    }
+    qemu_fprintf(f, "     FPCR=%08x FPSR=%08x\n",
+                 vfp_get_fpcr(env), vfp_get_fpsr(env));
+
+    if (cpu_isar_feature(aa64_sve, cpu) && sve_exception_el(env, el) == 0) {
+        int j, zcr_len = sve_zcr_len_for_el(env, el);
+
+        for (i = 0; i <= FFR_PRED_NUM; i++) {
+            bool eol;
+            if (i == FFR_PRED_NUM) {
+                qemu_fprintf(f, "FFR=");
+                /* It's last, so end the line.  */
+                eol = true;
+            } else {
+                qemu_fprintf(f, "P%02d=", i);
+                switch (zcr_len) {
+                case 0:
+                    eol = i % 8 == 7;
+                    break;
+                case 1:
+                    eol = i % 6 == 5;
+                    break;
+                case 2:
+                case 3:
+                    eol = i % 3 == 2;
+                    break;
+                default:
+                    /* More than one quadword per predicate.  */
+                    eol = true;
+                    break;
+                }
+            }
+            for (j = zcr_len / 4; j >= 0; j--) {
+                int digits;
+                if (j * 4 + 4 <= zcr_len + 1) {
+                    digits = 16;
+                } else {
+                    digits = (zcr_len % 4 + 1) * 4;
+                }
+                qemu_fprintf(f, "%0*" PRIx64 "%s", digits,
+                             env->vfp.pregs[i].p[j],
+                             j ? ":" : eol ? "\n" : " ");
+            }
+        }
+
+        for (i = 0; i < 32; i++) {
+            if (zcr_len == 0) {
+                qemu_fprintf(f, "Z%02d=%016" PRIx64 ":%016" PRIx64 "%s",
+                             i, env->vfp.zregs[i].d[1],
+                             env->vfp.zregs[i].d[0], i & 1 ? "\n" : " ");
+            } else if (zcr_len == 1) {
+                qemu_fprintf(f, "Z%02d=%016" PRIx64 ":%016" PRIx64
+                             ":%016" PRIx64 ":%016" PRIx64 "\n",
+                             i, env->vfp.zregs[i].d[3], env->vfp.zregs[i].d[2],
+                             env->vfp.zregs[i].d[1], env->vfp.zregs[i].d[0]);
+            } else {
+                for (j = zcr_len; j >= 0; j--) {
+                    bool odd = (zcr_len - j) % 2 != 0;
+                    if (j == zcr_len) {
+                        qemu_fprintf(f, "Z%02d[%x-%x]=", i, j, j - 1);
+                    } else if (!odd) {
+                        if (j > 0) {
+                            qemu_fprintf(f, "   [%x-%x]=", j, j - 1);
+                        } else {
+                            qemu_fprintf(f, "     [%x]=", j);
+                        }
+                    }
+                    qemu_fprintf(f, "%016" PRIx64 ":%016" PRIx64 "%s",
+                                 env->vfp.zregs[i].d[j * 2 + 1],
+                                 env->vfp.zregs[i].d[j * 2],
+                                 odd || j == 0 ? "\n" : ":");
+                }
+            }
+        }
+    } else {
+        for (i = 0; i < 32; i++) {
+            uint64_t *q = aa64_vfp_qreg(env, i);
+            qemu_fprintf(f, "Q%02d=%016" PRIx64 ":%016" PRIx64 "%s",
+                         i, q[1], q[0], (i & 1 ? "\n" : " "));
+        }
+    }
+}
 #endif
+
+void arm_cpu_dump_state(CPUState *cs, FILE *f, int flags)
+{
+    ARMCPU *cpu = ARM_CPU(cs);
+    CPUARMState *env = &cpu->env;
+    int i;
+
+    if (is_a64(env)) {
+        aarch64_cpu_dump_state(cs, f, flags);
+        return;
+    }
+
+    for (i = 0; i < 16; i++) {
+        qemu_fprintf(f, "R%02d=%08x", i, env->regs[i]);
+        if ((i % 4) == 3) {
+            qemu_fprintf(f, "\n");
+        } else {
+            qemu_fprintf(f, " ");
+        }
+    }
+
+    if (arm_feature(env, ARM_FEATURE_M)) {
+        uint32_t xpsr = xpsr_read(env);
+        const char *mode;
+        const char *ns_status = "";
+
+        if (arm_feature(env, ARM_FEATURE_M_SECURITY)) {
+            ns_status = env->v7m.secure ? "S " : "NS ";
+        }
+
+        if (xpsr & XPSR_EXCP) {
+            mode = "handler";
+        } else {
+            if (env->v7m.control[env->v7m.secure] & R_V7M_CONTROL_NPRIV_MASK) {
+                mode = "unpriv-thread";
+            } else {
+                mode = "priv-thread";
+            }
+        }
+
+        qemu_fprintf(f, "XPSR=%08x %c%c%c%c %c %s%s\n",
+                     xpsr,
+                     xpsr & XPSR_N ? 'N' : '-',
+                     xpsr & XPSR_Z ? 'Z' : '-',
+                     xpsr & XPSR_C ? 'C' : '-',
+                     xpsr & XPSR_V ? 'V' : '-',
+                     xpsr & XPSR_T ? 'T' : 'A',
+                     ns_status,
+                     mode);
+    } else {
+        uint32_t psr = cpsr_read(env);
+        const char *ns_status = "";
+
+        if (arm_feature(env, ARM_FEATURE_EL3) &&
+            (psr & CPSR_M) != ARM_CPU_MODE_MON) {
+            ns_status = env->cp15.scr_el3 & SCR_NS ? "NS " : "S ";
+        }
+
+        qemu_fprintf(f, "PSR=%08x %c%c%c%c %c %s%s%d\n",
+                     psr,
+                     psr & CPSR_N ? 'N' : '-',
+                     psr & CPSR_Z ? 'Z' : '-',
+                     psr & CPSR_C ? 'C' : '-',
+                     psr & CPSR_V ? 'V' : '-',
+                     psr & CPSR_T ? 'T' : 'A',
+                     ns_status,
+                     aarch32_mode_name(psr), (psr & 0x10) ? 32 : 26);
+    }
+
+    if (flags & CPU_DUMP_FPU) {
+        int numvfpregs = 0;
+        if (arm_feature(env, ARM_FEATURE_VFP)) {
+            numvfpregs += 16;
+        }
+        if (arm_feature(env, ARM_FEATURE_VFP3)) {
+            numvfpregs += 16;
+        }
+        for (i = 0; i < numvfpregs; i++) {
+            uint64_t v = *aa32_vfp_dreg(env, i);
+            qemu_fprintf(f, "s%02d=%08x s%02d=%08x d%02d=%016" PRIx64 "\n",
+                         i * 2, (uint32_t)v,
+                         i * 2 + 1, (uint32_t)(v >> 32),
+                         i, v);
+        }
+        qemu_fprintf(f, "FPSCR: %08x\n", vfp_get_fpscr(env));
+    }
+}
diff --git a/target/arm/internals.h b/target/arm/internals.h
index 06e676bf62..56281d8ece 100644
--- a/target/arm/internals.h
+++ b/target/arm/internals.h
@@ -1042,4 +1042,12 @@ bool pmsav8_mpu_lookup(CPUARMState *env, uint32_t address,
                        int *prot, bool *is_subpage,
                        ARMMMUFaultInfo *fi, uint32_t *mregion);
 
+#ifdef TARGET_AARCH64
+void aarch64_cpu_dump_state(CPUState *cs, FILE *f, int flags);
+#else
+static inline void aarch64_cpu_dump_state(CPUState *cs, FILE *f, int flags)
+{
+}
+#endif
+
 #endif
diff --git a/target/arm/translate-a64.c b/target/arm/translate-a64.c
index ae739f6575..8abe1f0e4f 100644
--- a/target/arm/translate-a64.c
+++ b/target/arm/translate-a64.c
@@ -152,133 +152,6 @@ static void set_btype(DisasContext *s, int val)
     s->btype = -1;
 }
 
-void aarch64_cpu_dump_state(CPUState *cs, FILE *f, int flags)
-{
-    ARMCPU *cpu = ARM_CPU(cs);
-    CPUARMState *env = &cpu->env;
-    uint32_t psr = pstate_read(env);
-    int i;
-    int el = arm_current_el(env);
-    const char *ns_status;
-
-    qemu_fprintf(f, " PC=%016" PRIx64 " ", env->pc);
-    for (i = 0; i < 32; i++) {
-        if (i == 31) {
-            qemu_fprintf(f, " SP=%016" PRIx64 "\n", env->xregs[i]);
-        } else {
-            qemu_fprintf(f, "X%02d=%016" PRIx64 "%s", i, env->xregs[i],
-                         (i + 2) % 3 ? " " : "\n");
-        }
-    }
-
-    if (arm_feature(env, ARM_FEATURE_EL3) && el != 3) {
-        ns_status = env->cp15.scr_el3 & SCR_NS ? "NS " : "S ";
-    } else {
-        ns_status = "";
-    }
-    qemu_fprintf(f, "PSTATE=%08x %c%c%c%c %sEL%d%c",
-                 psr,
-                 psr & PSTATE_N ? 'N' : '-',
-                 psr & PSTATE_Z ? 'Z' : '-',
-                 psr & PSTATE_C ? 'C' : '-',
-                 psr & PSTATE_V ? 'V' : '-',
-                 ns_status,
-                 el,
-                 psr & PSTATE_SP ? 'h' : 't');
-
-    if (cpu_isar_feature(aa64_bti, cpu)) {
-        qemu_fprintf(f, "  BTYPE=%d", (psr & PSTATE_BTYPE) >> 10);
-    }
-    if (!(flags & CPU_DUMP_FPU)) {
-        qemu_fprintf(f, "\n");
-        return;
-    }
-    if (fp_exception_el(env, el) != 0) {
-        qemu_fprintf(f, "    FPU disabled\n");
-        return;
-    }
-    qemu_fprintf(f, "     FPCR=%08x FPSR=%08x\n",
-                 vfp_get_fpcr(env), vfp_get_fpsr(env));
-
-    if (cpu_isar_feature(aa64_sve, cpu) && sve_exception_el(env, el) == 0) {
-        int j, zcr_len = sve_zcr_len_for_el(env, el);
-
-        for (i = 0; i <= FFR_PRED_NUM; i++) {
-            bool eol;
-            if (i == FFR_PRED_NUM) {
-                qemu_fprintf(f, "FFR=");
-                /* It's last, so end the line.  */
-                eol = true;
-            } else {
-                qemu_fprintf(f, "P%02d=", i);
-                switch (zcr_len) {
-                case 0:
-                    eol = i % 8 == 7;
-                    break;
-                case 1:
-                    eol = i % 6 == 5;
-                    break;
-                case 2:
-                case 3:
-                    eol = i % 3 == 2;
-                    break;
-                default:
-                    /* More than one quadword per predicate.  */
-                    eol = true;
-                    break;
-                }
-            }
-            for (j = zcr_len / 4; j >= 0; j--) {
-                int digits;
-                if (j * 4 + 4 <= zcr_len + 1) {
-                    digits = 16;
-                } else {
-                    digits = (zcr_len % 4 + 1) * 4;
-                }
-                qemu_fprintf(f, "%0*" PRIx64 "%s", digits,
-                             env->vfp.pregs[i].p[j],
-                             j ? ":" : eol ? "\n" : " ");
-            }
-        }
-
-        for (i = 0; i < 32; i++) {
-            if (zcr_len == 0) {
-                qemu_fprintf(f, "Z%02d=%016" PRIx64 ":%016" PRIx64 "%s",
-                             i, env->vfp.zregs[i].d[1],
-                             env->vfp.zregs[i].d[0], i & 1 ? "\n" : " ");
-            } else if (zcr_len == 1) {
-                qemu_fprintf(f, "Z%02d=%016" PRIx64 ":%016" PRIx64
-                             ":%016" PRIx64 ":%016" PRIx64 "\n",
-                             i, env->vfp.zregs[i].d[3], env->vfp.zregs[i].d[2],
-                             env->vfp.zregs[i].d[1], env->vfp.zregs[i].d[0]);
-            } else {
-                for (j = zcr_len; j >= 0; j--) {
-                    bool odd = (zcr_len - j) % 2 != 0;
-                    if (j == zcr_len) {
-                        qemu_fprintf(f, "Z%02d[%x-%x]=", i, j, j - 1);
-                    } else if (!odd) {
-                        if (j > 0) {
-                            qemu_fprintf(f, "   [%x-%x]=", j, j - 1);
-                        } else {
-                            qemu_fprintf(f, "     [%x]=", j);
-                        }
-                    }
-                    qemu_fprintf(f, "%016" PRIx64 ":%016" PRIx64 "%s",
-                                 env->vfp.zregs[i].d[j * 2 + 1],
-                                 env->vfp.zregs[i].d[j * 2],
-                                 odd || j == 0 ? "\n" : ":");
-                }
-            }
-        }
-    } else {
-        for (i = 0; i < 32; i++) {
-            uint64_t *q = aa64_vfp_qreg(env, i);
-            qemu_fprintf(f, "Q%02d=%016" PRIx64 ":%016" PRIx64 "%s",
-                         i, q[1], q[0], (i & 1 ? "\n" : " "));
-        }
-    }
-}
-
 void gen_a64_set_pc_im(uint64_t val)
 {
     tcg_gen_movi_i64(cpu_pc, val);
diff --git a/target/arm/translate.c b/target/arm/translate.c
index d0ab3e27e6..1e50627690 100644
--- a/target/arm/translate.c
+++ b/target/arm/translate.c
@@ -12416,93 +12416,6 @@ void gen_intermediate_code(CPUState *cpu, TranslationBlock *tb, int max_insns)
     translator_loop(ops, &dc.base, cpu, tb, max_insns);
 }
 
-void arm_cpu_dump_state(CPUState *cs, FILE *f, int flags)
-{
-    ARMCPU *cpu = ARM_CPU(cs);
-    CPUARMState *env = &cpu->env;
-    int i;
-
-    if (is_a64(env)) {
-        aarch64_cpu_dump_state(cs, f, flags);
-        return;
-    }
-
-    for (i = 0; i < 16; i++) {
-        qemu_fprintf(f, "R%02d=%08x", i, env->regs[i]);
-        if ((i % 4) == 3) {
-            qemu_fprintf(f, "\n");
-        } else {
-            qemu_fprintf(f, " ");
-        }
-    }
-
-    if (arm_feature(env, ARM_FEATURE_M)) {
-        uint32_t xpsr = xpsr_read(env);
-        const char *mode;
-        const char *ns_status = "";
-
-        if (arm_feature(env, ARM_FEATURE_M_SECURITY)) {
-            ns_status = env->v7m.secure ? "S " : "NS ";
-        }
-
-        if (xpsr & XPSR_EXCP) {
-            mode = "handler";
-        } else {
-            if (env->v7m.control[env->v7m.secure] & R_V7M_CONTROL_NPRIV_MASK) {
-                mode = "unpriv-thread";
-            } else {
-                mode = "priv-thread";
-            }
-        }
-
-        qemu_fprintf(f, "XPSR=%08x %c%c%c%c %c %s%s\n",
-                     xpsr,
-                     xpsr & XPSR_N ? 'N' : '-',
-                     xpsr & XPSR_Z ? 'Z' : '-',
-                     xpsr & XPSR_C ? 'C' : '-',
-                     xpsr & XPSR_V ? 'V' : '-',
-                     xpsr & XPSR_T ? 'T' : 'A',
-                     ns_status,
-                     mode);
-    } else {
-        uint32_t psr = cpsr_read(env);
-        const char *ns_status = "";
-
-        if (arm_feature(env, ARM_FEATURE_EL3) &&
-            (psr & CPSR_M) != ARM_CPU_MODE_MON) {
-            ns_status = env->cp15.scr_el3 & SCR_NS ? "NS " : "S ";
-        }
-
-        qemu_fprintf(f, "PSR=%08x %c%c%c%c %c %s%s%d\n",
-                     psr,
-                     psr & CPSR_N ? 'N' : '-',
-                     psr & CPSR_Z ? 'Z' : '-',
-                     psr & CPSR_C ? 'C' : '-',
-                     psr & CPSR_V ? 'V' : '-',
-                     psr & CPSR_T ? 'T' : 'A',
-                     ns_status,
-                     aarch32_mode_name(psr), (psr & 0x10) ? 32 : 26);
-    }
-
-    if (flags & CPU_DUMP_FPU) {
-        int numvfpregs = 0;
-        if (arm_feature(env, ARM_FEATURE_VFP)) {
-            numvfpregs += 16;
-        }
-        if (arm_feature(env, ARM_FEATURE_VFP3)) {
-            numvfpregs += 16;
-        }
-        for (i = 0; i < numvfpregs; i++) {
-            uint64_t v = *aa32_vfp_dreg(env, i);
-            qemu_fprintf(f, "s%02d=%08x s%02d=%08x d%02d=%016" PRIx64 "\n",
-                         i * 2, (uint32_t)v,
-                         i * 2 + 1, (uint32_t)(v >> 32),
-                         i, v);
-        }
-        qemu_fprintf(f, "FPSCR: %08x\n", vfp_get_fpscr(env));
-    }
-}
-
 void restore_state_to_opc(CPUARMState *env, TranslationBlock *tb,
                           target_ulong *data)
 {
diff --git a/target/arm/translate.h b/target/arm/translate.h
index dc06dce767..1dd3ac0a41 100644
--- a/target/arm/translate.h
+++ b/target/arm/translate.h
@@ -169,7 +169,6 @@ static inline void disas_set_insn_syndrome(DisasContext *s, uint32_t syn)
 #ifdef TARGET_AARCH64
 void a64_translate_init(void);
 void gen_a64_set_pc_im(uint64_t val);
-void aarch64_cpu_dump_state(CPUState *cs, FILE *f, int flags);
 extern const TranslatorOps aarch64_translator_ops;
 #else
 static inline void a64_translate_init(void)
@@ -179,10 +178,6 @@ static inline void a64_translate_init(void)
 static inline void gen_a64_set_pc_im(uint64_t val)
 {
 }
-
-static inline void aarch64_cpu_dump_state(CPUState *cs, FILE *f, int flags)
-{
-}
 #endif
 
 void arm_test_cc(DisasCompare *cmp, int cc);
-- 
2.20.1



^ permalink raw reply related	[flat|nested] 51+ messages in thread

* [Qemu-devel] [PATCH v2 19/23] target/arm: Move watchpoints APIs to helper.c
  2019-06-15 15:43 [Qemu-devel] [PATCH v2 00/23] Support disabling TCG on ARM Philippe Mathieu-Daudé
                   ` (17 preceding siblings ...)
  2019-06-15 15:43 ` [Qemu-devel] [PATCH v2 18/23] target/arm: Move CPU state dumping routines to helper.c Philippe Mathieu-Daudé
@ 2019-06-15 15:43 ` Philippe Mathieu-Daudé
  2019-06-17 14:46   ` [Qemu-devel] [Qemu-arm] " Alex Bennée
  2019-06-15 15:43 ` [Qemu-devel] [PATCH v2 20/23] target/arm: Define TCG dependent functions when TCG is enabled Philippe Mathieu-Daudé
                   ` (3 subsequent siblings)
  22 siblings, 1 reply; 51+ messages in thread
From: Philippe Mathieu-Daudé @ 2019-06-15 15:43 UTC (permalink / raw)
  To: qemu-devel
  Cc: Peter Maydell, qemu-arm, Philippe Mathieu-Daudé,
	Samuel Ortiz, Robert Bradford

From: Samuel Ortiz <sameo@linux.intel.com>

Here again, those APIs are not TCG dependent and can move to the always
built helper.c.

Signed-off-by: Samuel Ortiz <sameo@linux.intel.com>
Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com>
Reviewed-by: Robert Bradford <robert.bradford@intel.com>
[PMD: Rebased]
Signed-off-by: Philippe Mathieu-Daudé <philmd@redhat.com>
---
 target/arm/helper.c    | 213 +++++++++++++++++++++++++++++++++++++++++
 target/arm/internals.h |   6 ++
 target/arm/op_helper.c | 213 -----------------------------------------
 3 files changed, 219 insertions(+), 213 deletions(-)

diff --git a/target/arm/helper.c b/target/arm/helper.c
index 8c32b2bc0d..8b7ce0561b 100644
--- a/target/arm/helper.c
+++ b/target/arm/helper.c
@@ -11508,3 +11508,216 @@ void arm_cpu_dump_state(CPUState *cs, FILE *f, int flags)
         qemu_fprintf(f, "FPSCR: %08x\n", vfp_get_fpscr(env));
     }
 }
+
+/* Return true if the linked breakpoint entry lbn passes its checks */
+static bool linked_bp_matches(ARMCPU *cpu, int lbn)
+{
+    CPUARMState *env = &cpu->env;
+    uint64_t bcr = env->cp15.dbgbcr[lbn];
+    int brps = extract32(cpu->dbgdidr, 24, 4);
+    int ctx_cmps = 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<n>_EL1.LBN must indicate that breakpoint).
+     * We choose the former.
+     */
+    if (lbn > brps || lbn < (brps - ctx_cmps)) {
+        return false;
+    }
+
+    bcr = env->cp15.dbgbcr[lbn];
+
+    if (extract64(bcr, 0, 1) == 0) {
+        /* Linked breakpoint disabled : generate no events */
+        return false;
+    }
+
+    bt = 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 ASID),
+     * since we don't implement the optional v7 context ID masking.
+     */
+    contextidr = 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 == 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;
+}
+
+bool bp_wp_matches(ARMCPU *cpu, int n, bool is_wp)
+{
+    CPUARMState *env = &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 = arm_is_secure(env);
+    int access_el = arm_current_el(env);
+
+    if (is_wp) {
+        CPUWatchpoint *wp = env->cpu_watchpoint[n];
+
+        if (!wp || !(wp->flags & BP_WATCHPOINT_HIT)) {
+            return false;
+        }
+        cr = env->cp15.dbgwcr[n];
+        if (wp->hitattrs.user) {
+            /*
+             * The LDRT/STRT/LDT/STT "unprivileged access" instructions should
+             * match watchpoints as if they were accesses done at EL0, even if
+             * the CPU is at EL1 or higher.
+             */
+            access_el = 0;
+        }
+    } else {
+        uint64_t pc = is_a64(env) ? env->pc : env->regs[15];
+
+        if (!env->cpu_breakpoint[n] || env->cpu_breakpoint[n]->pc != pc) {
+            return false;
+        }
+        cr = 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 = extract64(cr, 1, 2);
+    hmc = extract64(cr, 13, 1);
+    ssc = 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) == 0) {
+            return false;
+        }
+        break;
+    case 0:
+        if (extract32(pac, 1, 1) == 0) {
+            return false;
+        }
+        break;
+    default:
+        g_assert_not_reached();
+    }
+
+    wt = extract64(cr, 20, 1);
+    lbn = extract64(cr, 16, 4);
+
+    if (wt && !linked_bp_matches(cpu, lbn)) {
+        return false;
+    }
+
+    return true;
+}
+
+static bool check_watchpoints(ARMCPU *cpu)
+{
+    CPUARMState *env = &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) == 0
+        || !arm_generate_debug_exceptions(env)) {
+        return false;
+    }
+
+    for (n = 0; n < ARRAY_SIZE(env->cpu_watchpoint); n++) {
+        if (bp_wp_matches(cpu, n, true)) {
+            return true;
+        }
+    }
+    return false;
+}
+
+bool arm_debug_check_watchpoint(CPUState *cs, CPUWatchpoint *wp)
+{
+    /*
+     * Called by core code when a CPU watchpoint fires; need to check if this
+     * is also an architectural watchpoint match.
+     */
+    ARMCPU *cpu = ARM_CPU(cs);
+
+    return check_watchpoints(cpu);
+}
+
+vaddr arm_adjust_watchpoint_address(CPUState *cs, vaddr addr, int len)
+{
+    ARMCPU *cpu = ARM_CPU(cs);
+    CPUARMState *env = &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 == 1) {
+            addr ^= 3;
+        } else if (len == 2) {
+            addr ^= 2;
+        }
+    }
+
+    return addr;
+}
diff --git a/target/arm/internals.h b/target/arm/internals.h
index 56281d8ece..fbbc701bb0 100644
--- a/target/arm/internals.h
+++ b/target/arm/internals.h
@@ -1042,6 +1042,12 @@ bool pmsav8_mpu_lookup(CPUARMState *env, uint32_t address,
                        int *prot, bool *is_subpage,
                        ARMMMUFaultInfo *fi, uint32_t *mregion);
 
+/*
+ * Returns true when the current CPU execution context matches
+ * the watchpoint or the breakpoint pointed at by n.
+ */
+bool bp_wp_matches(ARMCPU *cpu, int n, bool is_wp);
+
 #ifdef TARGET_AARCH64
 void aarch64_cpu_dump_state(CPUState *cs, FILE *f, int flags);
 #else
diff --git a/target/arm/op_helper.c b/target/arm/op_helper.c
index 63bce32810..68740e1b30 100644
--- a/target/arm/op_helper.c
+++ b/target/arm/op_helper.c
@@ -1018,185 +1018,6 @@ void HELPER(pre_smc)(CPUARMState *env, uint32_t syndrome)
     }
 }
 
-/* Return true if the linked breakpoint entry lbn passes its checks */
-static bool linked_bp_matches(ARMCPU *cpu, int lbn)
-{
-    CPUARMState *env = &cpu->env;
-    uint64_t bcr = env->cp15.dbgbcr[lbn];
-    int brps = extract32(cpu->dbgdidr, 24, 4);
-    int ctx_cmps = 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<n>_EL1.LBN must indicate that breakpoint).
-     * We choose the former.
-     */
-    if (lbn > brps || lbn < (brps - ctx_cmps)) {
-        return false;
-    }
-
-    bcr = env->cp15.dbgbcr[lbn];
-
-    if (extract64(bcr, 0, 1) == 0) {
-        /* Linked breakpoint disabled : generate no events */
-        return false;
-    }
-
-    bt = 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 ASID),
-     * since we don't implement the optional v7 context ID masking.
-     */
-    contextidr = 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 == 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 = &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 = arm_is_secure(env);
-    int access_el = arm_current_el(env);
-
-    if (is_wp) {
-        CPUWatchpoint *wp = env->cpu_watchpoint[n];
-
-        if (!wp || !(wp->flags & BP_WATCHPOINT_HIT)) {
-            return false;
-        }
-        cr = env->cp15.dbgwcr[n];
-        if (wp->hitattrs.user) {
-            /*
-             * The LDRT/STRT/LDT/STT "unprivileged access" instructions should
-             * match watchpoints as if they were accesses done at EL0, even if
-             * the CPU is at EL1 or higher.
-             */
-            access_el = 0;
-        }
-    } else {
-        uint64_t pc = is_a64(env) ? env->pc : env->regs[15];
-
-        if (!env->cpu_breakpoint[n] || env->cpu_breakpoint[n]->pc != pc) {
-            return false;
-        }
-        cr = 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 = extract64(cr, 1, 2);
-    hmc = extract64(cr, 13, 1);
-    ssc = 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) == 0) {
-            return false;
-        }
-        break;
-    case 0:
-        if (extract32(pac, 1, 1) == 0) {
-            return false;
-        }
-        break;
-    default:
-        g_assert_not_reached();
-    }
-
-    wt = extract64(cr, 20, 1);
-    lbn = extract64(cr, 16, 4);
-
-    if (wt && !linked_bp_matches(cpu, lbn)) {
-        return false;
-    }
-
-    return true;
-}
-
-static bool check_watchpoints(ARMCPU *cpu)
-{
-    CPUARMState *env = &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) == 0
-        || !arm_generate_debug_exceptions(env)) {
-        return false;
-    }
-
-    for (n = 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 = &cpu->env;
@@ -1227,40 +1048,6 @@ void HELPER(check_breakpoints)(CPUARMState *env)
     }
 }
 
-bool arm_debug_check_watchpoint(CPUState *cs, CPUWatchpoint *wp)
-{
-    /*
-     * Called by core code when a CPU watchpoint fires; need to check if this
-     * is also an architectural watchpoint match.
-     */
-    ARMCPU *cpu = ARM_CPU(cs);
-
-    return check_watchpoints(cpu);
-}
-
-vaddr arm_adjust_watchpoint_address(CPUState *cs, vaddr addr, int len)
-{
-    ARMCPU *cpu = ARM_CPU(cs);
-    CPUARMState *env = &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 == 1) {
-            addr ^= 3;
-        } else if (len == 2) {
-            addr ^= 2;
-        }
-    }
-
-    return addr;
-}
-
 void arm_debug_excp_handler(CPUState *cs)
 {
     /* Called by core code when a watchpoint or breakpoint fires;
-- 
2.20.1



^ permalink raw reply related	[flat|nested] 51+ messages in thread

* [Qemu-devel] [PATCH v2 20/23] target/arm: Define TCG dependent functions when TCG is enabled
  2019-06-15 15:43 [Qemu-devel] [PATCH v2 00/23] Support disabling TCG on ARM Philippe Mathieu-Daudé
                   ` (18 preceding siblings ...)
  2019-06-15 15:43 ` [Qemu-devel] [PATCH v2 19/23] target/arm: Move watchpoints APIs " Philippe Mathieu-Daudé
@ 2019-06-15 15:43 ` Philippe Mathieu-Daudé
  2019-06-17 14:50   ` Alex Bennée
  2019-06-15 15:43 ` [Qemu-devel] [PATCH v2 21/23] target/arm: Do not build TCG objects when TCG is off Philippe Mathieu-Daudé
                   ` (2 subsequent siblings)
  22 siblings, 1 reply; 51+ messages in thread
From: Philippe Mathieu-Daudé @ 2019-06-15 15:43 UTC (permalink / raw)
  To: qemu-devel
  Cc: Peter Maydell, qemu-arm, Philippe Mathieu-Daudé,
	Samuel Ortiz, Robert Bradford

From: Samuel Ortiz <sameo@linux.intel.com>

do_interrupt, do_unaligned_access, do_transaction_failed and debug_excp
are only relevant in the TCG context, so we should not define them
when TCG is disabled.

Signed-off-by: Samuel Ortiz <sameo@linux.intel.com>
Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com>
Reviewed-by: Robert Bradford <robert.bradford@intel.com>
[PMD: Rebased]
Signed-off-by: Philippe Mathieu-Daudé <philmd@redhat.com>
---
 target/arm/cpu.c | 8 +++++---
 1 file changed, 5 insertions(+), 3 deletions(-)

diff --git a/target/arm/cpu.c b/target/arm/cpu.c
index 2335659a85..3ffea857c4 100644
--- a/target/arm/cpu.c
+++ b/target/arm/cpu.c
@@ -1557,7 +1557,7 @@ static void arm_v7m_class_init(ObjectClass *oc, void *data)
     CPUClass *cc = CPU_CLASS(oc);
 
     acc->info = data;
-#ifndef CONFIG_USER_ONLY
+#if !defined(CONFIG_USER_ONLY) && defined(CONFIG_TCG)
     cc->do_interrupt = arm_v7m_cpu_do_interrupt;
 #endif
 
@@ -2172,22 +2172,24 @@ static void arm_cpu_class_init(ObjectClass *oc, void *data)
     cc->gdb_read_register = arm_cpu_gdb_read_register;
     cc->gdb_write_register = arm_cpu_gdb_write_register;
 #ifndef CONFIG_USER_ONLY
+#ifdef CONFIG_TCG
     cc->do_interrupt = arm_cpu_do_interrupt;
     cc->do_unaligned_access = arm_cpu_do_unaligned_access;
     cc->do_transaction_failed = arm_cpu_do_transaction_failed;
+    cc->debug_excp_handler = arm_debug_excp_handler;
+#endif /* CONFIG_TCG */
     cc->get_phys_page_attrs_debug = arm_cpu_get_phys_page_attrs_debug;
     cc->asidx_from_attrs = arm_asidx_from_attrs;
     cc->vmsd = &vmstate_arm_cpu;
     cc->virtio_is_big_endian = arm_cpu_virtio_is_big_endian;
     cc->write_elf64_note = arm_cpu_write_elf64_note;
     cc->write_elf32_note = arm_cpu_write_elf32_note;
-#endif
+#endif /* CONFIG_USER_ONLY */
     cc->gdb_num_core_regs = 26;
     cc->gdb_core_xml_file = "arm-core.xml";
     cc->gdb_arch_name = arm_gdb_arch_name;
     cc->gdb_get_dynamic_xml = arm_gdb_get_dynamic_xml;
     cc->gdb_stop_before_watchpoint = true;
-    cc->debug_excp_handler = arm_debug_excp_handler;
     cc->debug_check_watchpoint = arm_debug_check_watchpoint;
 #if !defined(CONFIG_USER_ONLY)
     cc->adjust_watchpoint_address = arm_adjust_watchpoint_address;
-- 
2.20.1



^ permalink raw reply related	[flat|nested] 51+ messages in thread

* [Qemu-devel] [PATCH v2 21/23] target/arm: Do not build TCG objects when TCG is off
  2019-06-15 15:43 [Qemu-devel] [PATCH v2 00/23] Support disabling TCG on ARM Philippe Mathieu-Daudé
                   ` (19 preceding siblings ...)
  2019-06-15 15:43 ` [Qemu-devel] [PATCH v2 20/23] target/arm: Define TCG dependent functions when TCG is enabled Philippe Mathieu-Daudé
@ 2019-06-15 15:43 ` Philippe Mathieu-Daudé
  2019-06-17 14:49   ` [Qemu-devel] [Qemu-arm] " Alex Bennée
  2019-06-15 15:43 ` [Qemu-devel] [RFC PATCH v2 22/23] target/arm: Restrict semi-hosting to TCG Philippe Mathieu-Daudé
  2019-06-15 15:43 ` [Qemu-devel] [NOTFORMERGE PATCH v2 23/23] Missing symbols when building with --disable-tcg Philippe Mathieu-Daudé
  22 siblings, 1 reply; 51+ messages in thread
From: Philippe Mathieu-Daudé @ 2019-06-15 15:43 UTC (permalink / raw)
  To: qemu-devel
  Cc: Peter Maydell, qemu-arm, Philippe Mathieu-Daudé,
	Samuel Ortiz, Robert Bradford

From: Samuel Ortiz <sameo@linux.intel.com>

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 <sameo@linux.intel.com>
Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com>
Reviewed-by: Robert Bradford <robert.bradford@intel.com>
[PMD: Rebased]
Signed-off-by: Philippe Mathieu-Daudé <philmd@redhat.com>
---

We can also use:

  ifeq ($(CONFIG_TCG),y)
  ...
  endif

But long single line with macros from rules.mak are way easier to
rebase. Now that this series is stable, I could change to ifeq if
required.

 target/arm/Makefile.objs | 18 +++++++++---------
 1 file changed, 9 insertions(+), 9 deletions(-)

diff --git a/target/arm/Makefile.objs b/target/arm/Makefile.objs
index 5f3f965cc6..b8aa9c032a 100644
--- a/target/arm/Makefile.objs
+++ b/target/arm/Makefile.objs
@@ -3,7 +3,7 @@ obj-y += cpu.o helper.o gdbstub.o
 obj-$(TARGET_AARCH64) += cpu64.o gdbstub64.o
 
 obj-$(CONFIG_SOFTMMU) += machine.o arch_dump.o monitor.o arm-powerctl.o
-obj-$(CONFIG_SOFTMMU) += psci.o
+obj-$(call land,$(CONFIG_TCG),$(CONFIG_SOFTMMU)) += psci.o
 
 obj-$(CONFIG_KVM) += kvm.o
 obj-$(call land,$(CONFIG_KVM),$(call lnot,$(TARGET_AARCH64))) += kvm32.o
@@ -31,12 +31,12 @@ 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
 
-obj-y += translate.o op_helper.o
-obj-y += crypto_helper.o
-obj-y += iwmmxt_helper.o vec_helper.o
-obj-y += neon_helper.o vfp_helper.o
-obj-$(call lor,$(CONFIG_USER_ONLY),$(CONFIG_ARM_V7M)) += v7m_helper.o
+obj-$(CONFIG_TCG) += translate.o op_helper.o
+obj-$(CONFIG_TCG) += crypto_helper.o
+obj-$(CONFIG_TCG) += iwmmxt_helper.o vec_helper.o
+obj-$(CONFIG_TCG) += neon_helper.o vfp_helper.o
+obj-$(call lor,$(CONFIG_USER_ONLY),$(call land,$(CONFIG_TCG),$(CONFIG_ARM_V7M))) += v7m_helper.o
 
-obj-$(TARGET_AARCH64) += translate-a64.o helper-a64.o
-obj-$(TARGET_AARCH64) += translate-sve.o sve_helper.o
-obj-$(TARGET_AARCH64) += pauth_helper.o
+obj-$(call land,$(CONFIG_TCG),$(TARGET_AARCH64)) += translate-a64.o helper-a64.o
+obj-$(call land,$(CONFIG_TCG),$(TARGET_AARCH64)) += translate-sve.o sve_helper.o
+obj-$(call land,$(CONFIG_TCG),$(TARGET_AARCH64)) += pauth_helper.o
-- 
2.20.1



^ permalink raw reply related	[flat|nested] 51+ messages in thread

* [Qemu-devel] [RFC PATCH v2 22/23] target/arm: Restrict semi-hosting to TCG
  2019-06-15 15:43 [Qemu-devel] [PATCH v2 00/23] Support disabling TCG on ARM Philippe Mathieu-Daudé
                   ` (20 preceding siblings ...)
  2019-06-15 15:43 ` [Qemu-devel] [PATCH v2 21/23] target/arm: Do not build TCG objects when TCG is off Philippe Mathieu-Daudé
@ 2019-06-15 15:43 ` Philippe Mathieu-Daudé
  2019-06-17 14:07   ` Alex Bennée
  2019-06-15 15:43 ` [Qemu-devel] [NOTFORMERGE PATCH v2 23/23] Missing symbols when building with --disable-tcg Philippe Mathieu-Daudé
  22 siblings, 1 reply; 51+ messages in thread
From: Philippe Mathieu-Daudé @ 2019-06-15 15:43 UTC (permalink / raw)
  To: qemu-devel; +Cc: Peter Maydell, qemu-arm, Philippe Mathieu-Daudé

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é <philmd@redhat.com>
---
 target/arm/helper.c | 8 +++++++-
 1 file changed, 7 insertions(+), 1 deletion(-)

diff --git a/target/arm/helper.c b/target/arm/helper.c
index 8b7ce0561b..a3843a5508 100644
--- a/target/arm/helper.c
+++ b/target/arm/helper.c
@@ -20,7 +20,6 @@
 #include "qemu/crc32c.h"
 #include "qemu/qemu-print.h"
 #include "exec/exec-all.h"
-#include "arm_ldst.h"
 #include <zlib.h> /* For crc32 */
 #include "hw/semihosting/semihost.h"
 #include "sysemu/cpus.h"
@@ -30,6 +29,9 @@
 #include "qapi/qapi-commands-target.h"
 #include "qapi/error.h"
 #include "qemu/guest-random.h"
+#ifdef CONFIG_TCG
+#include "arm_ldst.h"
+#endif
 
 #define ARM_CPU_FREQ 1000000000 /* FIXME: 1 GHz, should be configurable */
 
@@ -8270,6 +8272,7 @@ static void arm_cpu_do_interrupt_aarch64(CPUState *cs)
 
 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.
      */
@@ -8345,6 +8348,9 @@ static inline bool check_for_semihosting(CPUState *cs)
         env->regs[0] = do_arm_semihosting(env);
         return true;
     }
+#else
+    return false;
+#endif
 }
 
 /* Handle a CPU exception for A and R profile CPUs.
-- 
2.20.1



^ permalink raw reply related	[flat|nested] 51+ messages in thread

* [Qemu-devel] [NOTFORMERGE PATCH v2 23/23] Missing symbols when building with --disable-tcg
  2019-06-15 15:43 [Qemu-devel] [PATCH v2 00/23] Support disabling TCG on ARM Philippe Mathieu-Daudé
                   ` (21 preceding siblings ...)
  2019-06-15 15:43 ` [Qemu-devel] [RFC PATCH v2 22/23] target/arm: Restrict semi-hosting to TCG Philippe Mathieu-Daudé
@ 2019-06-15 15:43 ` Philippe Mathieu-Daudé
  2019-06-17 14:04   ` [Qemu-devel] [Qemu-arm] " Alex Bennée
  22 siblings, 1 reply; 51+ messages in thread
From: Philippe Mathieu-Daudé @ 2019-06-15 15:43 UTC (permalink / raw)
  To: qemu-devel; +Cc: Peter Maydell, qemu-arm, Philippe Mathieu-Daudé

While it might be normal to disable PSCI on KVM, I doubt the
VFP helpers are correct ;)

Anyway this allow to link the binary and run a KVM guest.

Tested using:

  $ make pc-bios/edk2-aarch64-code.fd
  $ dd if=/dev/zero of=flash1.img bs=1M count=64
  $ aarch64-softmmu/qemu-system-aarch64 \
    -nographic \
    -enable-kvm \
    -M virt,gic-version=3 \
    -cpu host \
    \
    -pflash pc-bios/edk2-aarch64-code.fd \
    -pflash flash1.img \
    -drive if=none,file=bionic-server-cloudimg-arm64.img,id=hd0 \
    -device virtio-blk-device,drive=hd0 \
    \
    -netdev type=user,id=net0 \
    -device virtio-net-device,netdev=net0

Signed-off-by: Philippe Mathieu-Daudé <philmd@redhat.com>
---
 target/arm/Makefile.objs |  1 +
 target/arm/kvm-missing.c | 22 ++++++++++++++++++++++
 2 files changed, 23 insertions(+)
 create mode 100644 target/arm/kvm-missing.c

diff --git a/target/arm/Makefile.objs b/target/arm/Makefile.objs
index b8aa9c032a..bf1cad2909 100644
--- a/target/arm/Makefile.objs
+++ b/target/arm/Makefile.objs
@@ -6,6 +6,7 @@ obj-$(CONFIG_SOFTMMU) += machine.o arch_dump.o monitor.o arm-powerctl.o
 obj-$(call land,$(CONFIG_TCG),$(CONFIG_SOFTMMU)) += psci.o
 
 obj-$(CONFIG_KVM) += kvm.o
+obj-$(CONFIG_KVM) += kvm-missing.o
 obj-$(call land,$(CONFIG_KVM),$(call lnot,$(TARGET_AARCH64))) += kvm32.o
 obj-$(call land,$(CONFIG_KVM),$(TARGET_AARCH64)) += kvm64.o
 obj-$(call lnot,$(CONFIG_KVM)) += kvm-stub.o
diff --git a/target/arm/kvm-missing.c b/target/arm/kvm-missing.c
new file mode 100644
index 0000000000..0b32cd4e9c
--- /dev/null
+++ b/target/arm/kvm-missing.c
@@ -0,0 +1,22 @@
+#include "qemu/osdep.h"
+#include "cpu.h"
+#include "internals.h"
+
+uint32_t vfp_get_fpscr(CPUARMState *env)
+{
+    return 0;
+}
+
+void vfp_set_fpscr(CPUARMState *env, uint32_t val)
+{
+}
+
+bool arm_is_psci_call(ARMCPU *cpu, int excp_type)
+{
+    return false;
+}
+
+void arm_handle_psci_call(ARMCPU *cpu)
+{
+    abort();
+}
-- 
2.20.1



^ permalink raw reply related	[flat|nested] 51+ messages in thread

* Re: [Qemu-devel] [Qemu-arm] [PATCH v2 01/23] target/arm: Makefile cleanup (Aarch64)
  2019-06-15 15:43 ` [Qemu-devel] [PATCH v2 01/23] target/arm: Makefile cleanup (Aarch64) Philippe Mathieu-Daudé
@ 2019-06-17 11:36   ` Alex Bennée
  0 siblings, 0 replies; 51+ messages in thread
From: Alex Bennée @ 2019-06-17 11:36 UTC (permalink / raw)
  To: qemu-arm; +Cc: Peter Maydell, Philippe Mathieu-Daudé, qemu-devel


Philippe Mathieu-Daudé <philmd@redhat.com> writes:

> Group Aarch64 objects together, TCG related ones at the bottom.
> This will help when restricting TCG-only objects.
>
> Signed-off-by: Philippe Mathieu-Daudé <philmd@redhat.com>

Reviewed-by: Alex Bennée <alex.bennee@linaro.org>

> ---
>  target/arm/Makefile.objs | 5 +++--
>  1 file changed, 3 insertions(+), 2 deletions(-)
>
> diff --git a/target/arm/Makefile.objs b/target/arm/Makefile.objs
> index dfa736a375..7c31fa01c1 100644
> --- a/target/arm/Makefile.objs
> +++ b/target/arm/Makefile.objs
> @@ -7,8 +7,7 @@ obj-$(call lnot,$(CONFIG_KVM)) += kvm-stub.o
>  obj-y += translate.o op_helper.o helper.o cpu.o
>  obj-y += neon_helper.o iwmmxt_helper.o vec_helper.o vfp_helper.o
>  obj-y += gdbstub.o
> -obj-$(TARGET_AARCH64) += cpu64.o translate-a64.o helper-a64.o gdbstub64.o
> -obj-$(TARGET_AARCH64) += pauth_helper.o
> +obj-$(TARGET_AARCH64) += cpu64.o gdbstub64.o
>  obj-y += crypto_helper.o
>  obj-$(CONFIG_SOFTMMU) += arm-powerctl.o
>
> @@ -33,4 +32,6 @@ 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
>
> +obj-$(TARGET_AARCH64) += translate-a64.o helper-a64.o
>  obj-$(TARGET_AARCH64) += translate-sve.o sve_helper.o
> +obj-$(TARGET_AARCH64) += pauth_helper.o


--
Alex Bennée


^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [Qemu-devel] [Qemu-arm] [PATCH v2 02/23] target/arm: Makefile cleanup (ARM)
  2019-06-15 15:43 ` [Qemu-devel] [PATCH v2 02/23] target/arm: Makefile cleanup (ARM) Philippe Mathieu-Daudé
@ 2019-06-17 11:36   ` Alex Bennée
  2019-06-17 11:37   ` Alex Bennée
  1 sibling, 0 replies; 51+ messages in thread
From: Alex Bennée @ 2019-06-17 11:36 UTC (permalink / raw)
  To: qemu-arm; +Cc: Peter Maydell, Philippe Mathieu-Daudé, qemu-devel


Philippe Mathieu-Daudé <philmd@redhat.com> writes:

> Group ARM objects together, TCG related ones at the bottom.
> This will help when restricting TCG-only objects.
>
> Signed-off-by: Philippe Mathieu-Daudé <philmd@redhat.com>

Reviewed-by: Alex Bennée <alex.bennee@linaro.org>

> ---
>  target/arm/Makefile.objs | 9 ++++++---
>  1 file changed, 6 insertions(+), 3 deletions(-)
>
> diff --git a/target/arm/Makefile.objs b/target/arm/Makefile.objs
> index 7c31fa01c1..3269dda613 100644
> --- a/target/arm/Makefile.objs
> +++ b/target/arm/Makefile.objs
> @@ -4,11 +4,9 @@ obj-$(CONFIG_KVM) += kvm.o
>  obj-$(call land,$(CONFIG_KVM),$(call lnot,$(TARGET_AARCH64))) += kvm32.o
>  obj-$(call land,$(CONFIG_KVM),$(TARGET_AARCH64)) += kvm64.o
>  obj-$(call lnot,$(CONFIG_KVM)) += kvm-stub.o
> -obj-y += translate.o op_helper.o helper.o cpu.o
> -obj-y += neon_helper.o iwmmxt_helper.o vec_helper.o vfp_helper.o
> +obj-y += helper.o cpu.o
>  obj-y += gdbstub.o
>  obj-$(TARGET_AARCH64) += cpu64.o gdbstub64.o
> -obj-y += crypto_helper.o
>  obj-$(CONFIG_SOFTMMU) += arm-powerctl.o
>
>  DECODETREE = $(SRC_PATH)/scripts/decodetree.py
> @@ -32,6 +30,11 @@ 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
>
> +obj-y += translate.o op_helper.o
> +obj-y += crypto_helper.o
> +obj-y += iwmmxt_helper.o vec_helper.o
> +obj-y += neon_helper.o vfp_helper.o
> +
>  obj-$(TARGET_AARCH64) += translate-a64.o helper-a64.o
>  obj-$(TARGET_AARCH64) += translate-sve.o sve_helper.o
>  obj-$(TARGET_AARCH64) += pauth_helper.o


--
Alex Bennée


^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [Qemu-devel] [Qemu-arm] [PATCH v2 02/23] target/arm: Makefile cleanup (ARM)
  2019-06-15 15:43 ` [Qemu-devel] [PATCH v2 02/23] target/arm: Makefile cleanup (ARM) Philippe Mathieu-Daudé
  2019-06-17 11:36   ` [Qemu-devel] [Qemu-arm] " Alex Bennée
@ 2019-06-17 11:37   ` Alex Bennée
  1 sibling, 0 replies; 51+ messages in thread
From: Alex Bennée @ 2019-06-17 11:37 UTC (permalink / raw)
  To: qemu-arm; +Cc: Peter Maydell, Philippe Mathieu-Daudé, qemu-devel


Philippe Mathieu-Daudé <philmd@redhat.com> writes:

> Group ARM objects together, TCG related ones at the bottom.
> This will help when restricting TCG-only objects.
>
> Signed-off-by: Philippe Mathieu-Daudé <philmd@redhat.com>

Reviewed-by: Alex Bennée <alex.bennee@linaro.org>

> ---
>  target/arm/Makefile.objs | 9 ++++++---
>  1 file changed, 6 insertions(+), 3 deletions(-)
>
> diff --git a/target/arm/Makefile.objs b/target/arm/Makefile.objs
> index 7c31fa01c1..3269dda613 100644
> --- a/target/arm/Makefile.objs
> +++ b/target/arm/Makefile.objs
> @@ -4,11 +4,9 @@ obj-$(CONFIG_KVM) += kvm.o
>  obj-$(call land,$(CONFIG_KVM),$(call lnot,$(TARGET_AARCH64))) += kvm32.o
>  obj-$(call land,$(CONFIG_KVM),$(TARGET_AARCH64)) += kvm64.o
>  obj-$(call lnot,$(CONFIG_KVM)) += kvm-stub.o
> -obj-y += translate.o op_helper.o helper.o cpu.o
> -obj-y += neon_helper.o iwmmxt_helper.o vec_helper.o vfp_helper.o
> +obj-y += helper.o cpu.o
>  obj-y += gdbstub.o
>  obj-$(TARGET_AARCH64) += cpu64.o gdbstub64.o
> -obj-y += crypto_helper.o
>  obj-$(CONFIG_SOFTMMU) += arm-powerctl.o
>
>  DECODETREE = $(SRC_PATH)/scripts/decodetree.py
> @@ -32,6 +30,11 @@ 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
>
> +obj-y += translate.o op_helper.o
> +obj-y += crypto_helper.o
> +obj-y += iwmmxt_helper.o vec_helper.o
> +obj-y += neon_helper.o vfp_helper.o
> +
>  obj-$(TARGET_AARCH64) += translate-a64.o helper-a64.o
>  obj-$(TARGET_AARCH64) += translate-sve.o sve_helper.o
>  obj-$(TARGET_AARCH64) += pauth_helper.o


--
Alex Bennée


^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [Qemu-devel] [Qemu-arm] [PATCH v2 03/23] target/arm: Makefile cleanup (KVM)
  2019-06-15 15:43 ` [Qemu-devel] [PATCH v2 03/23] target/arm: Makefile cleanup (KVM) Philippe Mathieu-Daudé
@ 2019-06-17 11:37   ` Alex Bennée
  0 siblings, 0 replies; 51+ messages in thread
From: Alex Bennée @ 2019-06-17 11:37 UTC (permalink / raw)
  To: qemu-arm; +Cc: Peter Maydell, Philippe Mathieu-Daudé, qemu-devel


Philippe Mathieu-Daudé <philmd@redhat.com> writes:

> Group KVM objects together.
>
> Signed-off-by: Philippe Mathieu-Daudé <philmd@redhat.com>

Reviewed-by: Alex Bennée <alex.bennee@linaro.org>

> ---
>  target/arm/Makefile.objs | 9 +++++----
>  1 file changed, 5 insertions(+), 4 deletions(-)
>
> diff --git a/target/arm/Makefile.objs b/target/arm/Makefile.objs
> index 3269dda613..626e340f55 100644
> --- a/target/arm/Makefile.objs
> +++ b/target/arm/Makefile.objs
> @@ -1,14 +1,15 @@
>  obj-y += arm-semi.o
>  obj-$(CONFIG_SOFTMMU) += machine.o psci.o arch_dump.o monitor.o
> -obj-$(CONFIG_KVM) += kvm.o
> -obj-$(call land,$(CONFIG_KVM),$(call lnot,$(TARGET_AARCH64))) += kvm32.o
> -obj-$(call land,$(CONFIG_KVM),$(TARGET_AARCH64)) += kvm64.o
> -obj-$(call lnot,$(CONFIG_KVM)) += kvm-stub.o
>  obj-y += helper.o cpu.o
>  obj-y += gdbstub.o
>  obj-$(TARGET_AARCH64) += cpu64.o gdbstub64.o
>  obj-$(CONFIG_SOFTMMU) += arm-powerctl.o
>
> +obj-$(CONFIG_KVM) += kvm.o
> +obj-$(call land,$(CONFIG_KVM),$(call lnot,$(TARGET_AARCH64))) += kvm32.o
> +obj-$(call land,$(CONFIG_KVM),$(TARGET_AARCH64)) += kvm64.o
> +obj-$(call lnot,$(CONFIG_KVM)) += kvm-stub.o
> +
>  DECODETREE = $(SRC_PATH)/scripts/decodetree.py
>
>  target/arm/decode-sve.inc.c: $(SRC_PATH)/target/arm/sve.decode $(DECODETREE)


--
Alex Bennée


^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [Qemu-devel] [Qemu-arm] [PATCH v2 04/23] target/arm: Makefile cleanup (softmmu)
  2019-06-15 15:43 ` [Qemu-devel] [PATCH v2 04/23] target/arm: Makefile cleanup (softmmu) Philippe Mathieu-Daudé
@ 2019-06-17 11:38   ` Alex Bennée
  0 siblings, 0 replies; 51+ messages in thread
From: Alex Bennée @ 2019-06-17 11:38 UTC (permalink / raw)
  To: qemu-arm; +Cc: Peter Maydell, Philippe Mathieu-Daudé, qemu-devel


Philippe Mathieu-Daudé <philmd@redhat.com> writes:

> Group SOFTMMU objects together.
>
> Signed-off-by: Philippe Mathieu-Daudé <philmd@redhat.com>

Reviewed-by: Alex Bennée <alex.bennee@linaro.org>

> ---
>  target/arm/Makefile.objs | 8 ++++----
>  1 file changed, 4 insertions(+), 4 deletions(-)
>
> diff --git a/target/arm/Makefile.objs b/target/arm/Makefile.objs
> index 626e340f55..72b42f825f 100644
> --- a/target/arm/Makefile.objs
> +++ b/target/arm/Makefile.objs
> @@ -1,9 +1,9 @@
>  obj-y += arm-semi.o
> -obj-$(CONFIG_SOFTMMU) += machine.o psci.o arch_dump.o monitor.o
> -obj-y += helper.o cpu.o
> -obj-y += gdbstub.o
> +obj-y += cpu.o helper.o gdbstub.o
>  obj-$(TARGET_AARCH64) += cpu64.o gdbstub64.o
> -obj-$(CONFIG_SOFTMMU) += arm-powerctl.o
> +
> +obj-$(CONFIG_SOFTMMU) += machine.o arch_dump.o monitor.o arm-powerctl.o
> +obj-$(CONFIG_SOFTMMU) += psci.o
>
>  obj-$(CONFIG_KVM) += kvm.o
>  obj-$(call land,$(CONFIG_KVM),$(call lnot,$(TARGET_AARCH64))) += kvm32.o


--
Alex Bennée


^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [Qemu-devel] [Qemu-arm] [PATCH v2 05/23] target/arm: Add copyright boilerplate
  2019-06-15 15:43 ` [Qemu-devel] [PATCH v2 05/23] target/arm: Add copyright boilerplate Philippe Mathieu-Daudé
@ 2019-06-17 11:39   ` Alex Bennée
  0 siblings, 0 replies; 51+ messages in thread
From: Alex Bennée @ 2019-06-17 11:39 UTC (permalink / raw)
  To: qemu-arm
  Cc: Peter Maydell, Philippe Mathieu-Daudé,
	qemu-devel, Robert Bradford, Samuel Ortiz


Philippe Mathieu-Daudé <philmd@redhat.com> writes:

> Signed-off-by: Philippe Mathieu-Daudé <philmd@redhat.com>
> Reviewed-by: Robert Bradford <robert.bradford@intel.com>
> Reviewed-by: Samuel Ortiz <sameo@linux.intel.com>

Reviewed-by: Alex Bennée <alex.bennee@linaro.org>

> ---
>  target/arm/helper.c | 7 +++++++
>  1 file changed, 7 insertions(+)
>
> diff --git a/target/arm/helper.c b/target/arm/helper.c
> index df4276f5f6..d3f3cb57d5 100644
> --- a/target/arm/helper.c
> +++ b/target/arm/helper.c
> @@ -1,3 +1,10 @@
> +/*
> + * 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"


--
Alex Bennée


^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [Qemu-devel] [Qemu-arm] [PATCH v2 06/23] target/arm: Fix multiline comment syntax
  2019-06-15 15:43 ` [Qemu-devel] [PATCH v2 06/23] target/arm: Fix multiline comment syntax Philippe Mathieu-Daudé
@ 2019-06-17 11:40   ` Alex Bennée
  0 siblings, 0 replies; 51+ messages in thread
From: Alex Bennée @ 2019-06-17 11:40 UTC (permalink / raw)
  To: qemu-arm; +Cc: Peter Maydell, Philippe Mathieu-Daudé, qemu-devel


Philippe Mathieu-Daudé <philmd@redhat.com> writes:

> Since commit 8c06fbdf36b checkpatch.pl enforce a new multiline
> comment syntax. Since we'll move this code around, fix its style
> first.
>
> Signed-off-by: Philippe Mathieu-Daudé <philmd@redhat.com>

Reviewed-by: Alex Bennée <alex.bennee@linaro.org>

> ---
>  target/arm/helper.c    | 213 +++++++++++++++++++++++++++--------------
>  target/arm/op_helper.c |  27 ++++--
>  2 files changed, 160 insertions(+), 80 deletions(-)
>
> diff --git a/target/arm/helper.c b/target/arm/helper.c
> index d3f3cb57d5..9a3766b759 100644
> --- a/target/arm/helper.c
> +++ b/target/arm/helper.c
> @@ -7531,7 +7531,8 @@ void HELPER(v7m_vlldm)(CPUARMState *env, uint32_t fptr)
>
>  uint32_t HELPER(v7m_tt)(CPUARMState *env, uint32_t addr, uint32_t op)
>  {
> -    /* The TT instructions can be used by unprivileged code, but in
> +    /*
> +     * 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
> @@ -7803,7 +7804,8 @@ static bool v7m_stack_write(ARMCPU *cpu, uint32_t addr, uint32_t value,
>      return true;
>
>  pend_fault:
> -    /* By pending the exception at this point we are making
> +    /*
> +     * 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
> @@ -7878,7 +7880,8 @@ static bool v7m_stack_read(ARMCPU *cpu, uint32_t *dest, uint32_t addr,
>      return true;
>
>  pend_fault:
> -    /* By pending the exception at this point we are making
> +    /*
> +     * 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
> @@ -7979,7 +7982,8 @@ void HELPER(v7m_preserve_fp_state)(CPUARMState *env)
>       */
>  }
>
> -/* Write to v7M CONTROL.SPSEL bit for the specified security bank.
> +/*
> + * 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.
> @@ -8007,7 +8011,8 @@ static void write_v7m_control_spsel_for_secstate(CPUARMState *env,
>      }
>  }
>
> -/* Write to v7M CONTROL.SPSEL bit. This may change the current
> +/*
> + * 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)
> @@ -8017,7 +8022,8 @@ static void write_v7m_control_spsel(CPUARMState *env, bool new_spsel)
>
>  void write_v7m_exception(CPUARMState *env, uint32_t new_exc)
>  {
> -    /* Write a new value to v7m.exception, thus transitioning into or out
> +    /*
> +     * Write a new value to v7m.exception, thus transitioning into or out
>       * of Handler mode; this may result in a change of active stack pointer.
>       */
>      bool new_is_psp, old_is_psp = v7m_using_psp(env);
> @@ -8043,7 +8049,8 @@ static void switch_v7m_security_state(CPUARMState *env, bool new_secstate)
>          return;
>      }
>
> -    /* All the banked state is accessed by looking at env->v7m.secure
> +    /*
> +     * All the banked state is accessed by looking at env->v7m.secure
>       * except for the stack pointer; rearrange the SP appropriately.
>       */
>      new_ss_msp = env->v7m.other_ss_msp;
> @@ -8070,7 +8077,8 @@ static void switch_v7m_security_state(CPUARMState *env, bool new_secstate)
>
>  void HELPER(v7m_bxns)(CPUARMState *env, uint32_t dest)
>  {
> -    /* Handle v7M BXNS:
> +    /*
> +     * 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
>       */
> @@ -8085,7 +8093,8 @@ void HELPER(v7m_bxns)(CPUARMState *env, uint32_t dest)
>      }
>
>      if (dest >= min_magic) {
> -        /* This is an exception return magic value; put it where
> +        /*
> +         * 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 complete"
> @@ -8110,7 +8119,8 @@ void HELPER(v7m_bxns)(CPUARMState *env, uint32_t dest)
>
>  void HELPER(v7m_blxns)(CPUARMState *env, uint32_t dest)
>  {
> -    /* Handle v7M BLXNS:
> +    /*
> +     * Handle v7M BLXNS:
>       *  - bit 0 of the destination address is the target security state
>       */
>
> @@ -8123,7 +8133,8 @@ void HELPER(v7m_blxns)(CPUARMState *env, uint32_t dest)
>      assert(env->v7m.secure);
>
>      if (dest & 1) {
> -        /* target is Secure, so this is just a normal BLX,
> +        /*
> +         * Target is Secure, so this is just a normal BLX,
>           * except that the low bit doesn't indicate Thumb/not.
>           */
>          env->regs[14] = nextinst;
> @@ -8154,7 +8165,8 @@ void HELPER(v7m_blxns)(CPUARMState *env, uint32_t dest)
>      env->regs[13] = sp;
>      env->regs[14] = 0xfeffffff;
>      if (arm_v7m_is_handler_mode(env)) {
> -        /* Write a dummy value to IPSR, to avoid leaking the current secure
> +        /*
> +         * 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.
>           */
> @@ -8169,7 +8181,8 @@ void HELPER(v7m_blxns)(CPUARMState *env, uint32_t dest)
>  static uint32_t *get_v7m_sp_ptr(CPUARMState *env, bool secure, bool threadmode,
>                                  bool spsel)
>  {
> -    /* Return a pointer to the location where we currently store the
> +    /*
> +     * 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
> @@ -8215,7 +8228,8 @@ static bool arm_v7m_load_vector(ARMCPU *cpu, int exc, bool targets_secure,
>
>      mmu_idx = 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
> +    /*
> +     * 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()
> @@ -8246,7 +8260,8 @@ static bool arm_v7m_load_vector(ARMCPU *cpu, int exc, bool targets_secure,
>      return true;
>
>  load_fail:
> -    /* All vector table fetch fails are reported as HardFault, with
> +    /*
> +     * 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,
> @@ -8278,7 +8293,8 @@ static uint32_t v7m_integrity_sig(CPUARMState *env, uint32_t lr)
>  static bool v7m_push_callee_stack(ARMCPU *cpu, uint32_t lr, bool dotailchain,
>                                    bool ignore_faults)
>  {
> -    /* For v8M, push the callee-saves register part of the stack frame.
> +    /*
> +     * 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.
>       */
> @@ -8329,7 +8345,8 @@ static bool v7m_push_callee_stack(ARMCPU *cpu, uint32_t lr, bool dotailchain,
>          return true;
>      }
>
> -    /* Write as much of the stack frame as we can. A write failure may
> +    /*
> +     * Write as much of the stack frame as we can. A write failure may
>       * cause us to pend a derived exception.
>       */
>      sig = v7m_integrity_sig(env, lr);
> @@ -8353,7 +8370,8 @@ static bool v7m_push_callee_stack(ARMCPU *cpu, uint32_t lr, bool dotailchain,
>  static void v7m_exception_taken(ARMCPU *cpu, uint32_t lr, bool dotailchain,
>                                  bool ignore_stackfaults)
>  {
> -    /* Do the "take the exception" parts of exception entry,
> +    /*
> +     * 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.
>       */
> @@ -8378,13 +8396,15 @@ static void v7m_exception_taken(ARMCPU *cpu, uint32_t lr, bool dotailchain,
>      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
> +            /*
> +             * 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
> +                    /*
> +                     * 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
> @@ -8393,7 +8413,8 @@ static void v7m_exception_taken(ARMCPU *cpu, uint32_t lr, bool dotailchain,
>                      lr &= ~R_V7M_EXCRET_DCRS_MASK;
>                  }
>              } else {
> -                /* We're going to a non-secure exception; push the
> +                /*
> +                 * We're going to a non-secure exception; push the
>                   * callee-saves registers to the stack now, if they're
>                   * not already saved.
>                   */
> @@ -8415,14 +8436,16 @@ static void v7m_exception_taken(ARMCPU *cpu, uint32_t lr, bool dotailchain,
>              lr |= R_V7M_EXCRET_SPSEL_MASK;
>          }
>
> -        /* Clear registers if necessary to prevent non-secure exception
> +        /*
> +         * 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
> +                /*
> +                 * 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
> @@ -8443,7 +8466,8 @@ static void v7m_exception_taken(ARMCPU *cpu, uint32_t lr, bool dotailchain,
>      }
>
>      if (push_failed && !ignore_stackfaults) {
> -        /* Derived exception on callee-saves register stacking:
> +        /*
> +         * 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.
>           */
> @@ -8460,7 +8484,8 @@ static void v7m_exception_taken(ARMCPU *cpu, uint32_t lr, bool dotailchain,
>          return;
>      }
>
> -    /* Now we've done everything that might cause a derived exception
> +    /*
> +     * 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).
>       */
> @@ -8663,7 +8688,8 @@ void HELPER(v7m_vlldm)(CPUARMState *env, uint32_t fptr)
>
>  static bool v7m_push_stack(ARMCPU *cpu)
>  {
> -    /* Do the "set up stack frame" part of exception entry,
> +    /*
> +     * 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
> @@ -8731,7 +8757,8 @@ static bool v7m_push_stack(ARMCPU *cpu)
>          }
>      }
>
> -    /* Write as much of the stack frame as we can. If we fail a stack
> +    /*
> +     * 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).
> @@ -8848,7 +8875,8 @@ static void do_v7m_exception_exit(ARMCPU *cpu)
>      bool ftype;
>      bool restore_s16_s31;
>
> -    /* If we're not in Handler mode then jumps to magic exception-exit
> +    /*
> +     * 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
> @@ -8862,7 +8890,8 @@ static void do_v7m_exception_exit(ARMCPU *cpu)
>          return;
>      }
>
> -    /* In the spec pseudocode ExceptionReturn() is called directly
> +    /*
> +     * 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
> @@ -8895,7 +8924,8 @@ static void do_v7m_exception_exit(ARMCPU *cpu)
>      }
>
>      if (arm_feature(env, ARM_FEATURE_M_SECURITY)) {
> -        /* EXC_RETURN.ES validation check (R_SMFL). We must do this before
> +        /*
> +         * EXC_RETURN.ES validation check (R_SMFL). We must do this before
>           * we pick which FAULTMASK to clear.
>           */
>          if (!env->v7m.secure &&
> @@ -8909,7 +8939,8 @@ static void do_v7m_exception_exit(ARMCPU *cpu)
>      }
>
>      if (env->v7m.exception != ARMV7M_EXCP_NMI) {
> -        /* Auto-clear FAULTMASK on return from other than 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 >= 0; the
>           * value of the ES bit in the exception return value indicates
> @@ -8934,7 +8965,8 @@ static void do_v7m_exception_exit(ARMCPU *cpu)
>          /* still an irq active now */
>          break;
>      case 1:
> -        /* we returned to base exception level, no nesting.
> +        /*
> +         * We returned to base exception level, no nesting.
>           * (In the pseudocode this is written using "NestedActivation != 1"
>           * where we have 'rettobase == false'.)
>           */
> @@ -8951,7 +8983,8 @@ static void do_v7m_exception_exit(ARMCPU *cpu)
>
>      if (arm_feature(env, ARM_FEATURE_V8)) {
>          if (!arm_feature(env, ARM_FEATURE_M_SECURITY)) {
> -            /* UNPREDICTABLE if S == 1 or DCRS == 0 or ES == 1 (R_XLCP);
> +            /*
> +             * UNPREDICTABLE if S == 1 or DCRS == 0 or ES == 1 (R_XLCP);
>               * we choose to take the UsageFault.
>               */
>              if ((excret & R_V7M_EXCRET_S_MASK) ||
> @@ -8970,7 +9003,8 @@ static void do_v7m_exception_exit(ARMCPU *cpu)
>              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
> +            /*
> +             * We only need to check NONBASETHRDENA for v7M, because in
>               * v8M this bit does not exist (it is RES1).
>               */
>              if (!rettobase &&
> @@ -9028,7 +9062,8 @@ static void do_v7m_exception_exit(ARMCPU *cpu)
>      }
>
>      if (ufault) {
> -        /* Bad exception return: instead of popping the exception
> +        /*
> +         * Bad exception return: instead of popping the exception
>           * stack, directly take a usage fault on the current stack.
>           */
>          env->v7m.cfsr[env->v7m.secure] |= R_V7M_CFSR_INVPC_MASK;
> @@ -9058,7 +9093,8 @@ static void do_v7m_exception_exit(ARMCPU *cpu)
>      switch_v7m_security_state(env, return_to_secure);
>
>      {
> -        /* The stack pointer we should be reading the exception frame from
> +        /*
> +         * 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
> @@ -9131,7 +9167,8 @@ static void do_v7m_exception_exit(ARMCPU *cpu)
>              v7m_stack_read(cpu, &xpsr, frameptr + 0x1c, mmu_idx);
>
>          if (!pop_ok) {
> -            /* v7m_stack_read() pended a fault, so take it (as a tail
> +            /*
> +             * 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");
> @@ -9139,7 +9176,8 @@ static void do_v7m_exception_exit(ARMCPU *cpu)
>              return;
>          }
>
> -        /* Returning from an exception with a PC with bit 0 set is defined
> +        /*
> +         * 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 specified
>           * to be UNPREDICTABLE. In practice actual v7M hardware seems to ignore
>           * the lsbit, and there are several RTOSes out there which incorrectly
> @@ -9157,13 +9195,15 @@ static void do_v7m_exception_exit(ARMCPU *cpu)
>          }
>
>          if (arm_feature(env, ARM_FEATURE_V8)) {
> -            /* For v8M we have to check whether the xPSR exception field
> +            /*
> +             * 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 = (xpsr & XPSR_EXCP) != 0;
>              if (return_to_handler != will_be_handler) {
> -                /* Take an INVPC UsageFault on the current stack.
> +                /*
> +                 * Take an INVPC UsageFault on the current stack.
>                   * By this point we will have switched to the security state
>                   * for the background state, so this UsageFault will target
>                   * that state.
> @@ -9278,7 +9318,8 @@ static void do_v7m_exception_exit(ARMCPU *cpu)
>                  frameptr += 0x40;
>              }
>          }
> -        /* Undo stack alignment (the SPREALIGN bit indicates that the original
> +        /*
> +         * Undo stack alignment (the SPREALIGN bit indicates that the original
>           * 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. (Adding 4
> @@ -9304,13 +9345,15 @@ static void do_v7m_exception_exit(ARMCPU *cpu)
>                                                 V7M_CONTROL, SFPA, sfpa);
>      }
>
> -    /* The restored xPSR exception field will be zero if we're
> +    /*
> +     * 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 != arm_v7m_is_handler_mode(env)) {
> -        /* Take an INVPC UsageFault by pushing the stack again;
> +        /*
> +         * Take an INVPC UsageFault by pushing the stack again;
>           * we know we're v7M so this is never a Secure UsageFault.
>           */
>          bool ignore_stackfaults;
> @@ -9332,7 +9375,8 @@ static void do_v7m_exception_exit(ARMCPU *cpu)
>
>  static bool do_v7m_function_return(ARMCPU *cpu)
>  {
> -    /* v8M security extensions magic function return.
> +    /*
> +     * v8M security extensions magic function return.
>       * We may either:
>       *  (1) throw an exception (longjump)
>       *  (2) return true if we successfully handled the function return
> @@ -9362,7 +9406,8 @@ static bool do_v7m_function_return(ARMCPU *cpu)
>          frame_sp_p = get_v7m_sp_ptr(env, true, threadmode, spsel);
>          frameptr = *frame_sp_p;
>
> -        /* These loads may throw an exception (for MPU faults). We want to
> +        /*
> +         * 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 = arm_v7m_mmu_idx_for_secstate(env, true);
> @@ -9443,7 +9488,8 @@ static void arm_log_exception(int idx)
>  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 success,
> +    /*
> +     * Load a 16-bit portion of a v7M instruction, returning true on success,
>       * or false on failure (in which case we will have pended the appropriate
>       * exception).
>       * We need to do the instruction fetch's MPU and SAU checks
> @@ -9466,7 +9512,8 @@ static bool v7m_read_half_insn(ARMCPU *cpu, ARMMMUIdx mmu_idx,
>
>      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
> +        /*
> +         * 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 |= R_V7M_SFSR_INVEP_MASK;
> @@ -9496,7 +9543,8 @@ static bool v7m_read_half_insn(ARMCPU *cpu, ARMMMUIdx mmu_idx,
>
>  static bool v7m_handle_execute_nsc(ARMCPU *cpu)
>  {
> -    /* Check whether this attempt to execute code in a Secure & NS-Callable
> +    /*
> +     * 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.
> @@ -9505,7 +9553,8 @@ static bool v7m_handle_execute_nsc(ARMCPU *cpu)
>      ARMMMUIdx mmu_idx;
>      uint16_t insn;
>
> -    /* We should never get here unless get_phys_addr_pmsav8() caused
> +    /*
> +     * We should never get here unless get_phys_addr_pmsav8() caused
>       * an exception for NS executing in S&NSC memory.
>       */
>      assert(!env->v7m.secure);
> @@ -9523,7 +9572,8 @@ static bool v7m_handle_execute_nsc(ARMCPU *cpu)
>      }
>
>      if (insn != 0xe97f) {
> -        /* Not an SG instruction first half (we choose the IMPDEF
> +        /*
> +         * Not an SG instruction first half (we choose the IMPDEF
>           * early-SG-check option).
>           */
>          goto gen_invep;
> @@ -9534,13 +9584,15 @@ static bool v7m_handle_execute_nsc(ARMCPU *cpu)
>      }
>
>      if (insn != 0xe97f) {
> -        /* Not an SG instruction second half (yes, both halves of the SG
> +        /*
> +         * 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.
> +    /*
> +     * 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" PRIx32
> @@ -9569,8 +9621,10 @@ void arm_v7m_cpu_do_interrupt(CPUState *cs)
>
>      arm_log_exception(cs->exception_index);
>
> -    /* For exceptions we just mark as pending on the NVIC, and let that
> -       handle it.  */
> +    /*
> +     * 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.secure);
> @@ -9616,13 +9670,15 @@ void arm_v7m_cpu_do_interrupt(CPUState *cs)
>          break;
>      case EXCP_PREFETCH_ABORT:
>      case EXCP_DATA_ABORT:
> -        /* Note that for M profile we don't have a guest facing FSR, but
> +        /*
> +         * 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 address
> +            /*
> +             * Exception generated when we try to execute code at an address
>               * 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
> @@ -9635,7 +9691,8 @@ void arm_v7m_cpu_do_interrupt(CPUState *cs)
>              }
>              break;
>          case M_FAKE_FSR_SFAULT:
> -            /* Various flavours of SecureFault for attempts to execute or
> +            /*
> +             * Various flavours of SecureFault for attempts to execute or
>               * access data in the wrong security state.
>               */
>              switch (cs->exception_index) {
> @@ -9677,7 +9734,8 @@ void arm_v7m_cpu_do_interrupt(CPUState *cs)
>              armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_BUS, false);
>              break;
>          default:
> -            /* All other FSR values are either MPU faults or "can't happen
> +            /*
> +             * All other FSR values are either MPU faults or "can't happen
>               * for M profile" cases.
>               */
>              switch (cs->exception_index) {
> @@ -9743,7 +9801,8 @@ void arm_v7m_cpu_do_interrupt(CPUState *cs)
>      if (arm_feature(env, ARM_FEATURE_V8)) {
>          lr = R_V7M_EXCRET_RES1_MASK |
>              R_V7M_EXCRET_DCRS_MASK;
> -        /* The S bit indicates whether we should return to Secure
> +        /*
> +         * 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
> @@ -12760,7 +12819,8 @@ uint32_t HELPER(v7m_mrs)(CPUARMState *env, uint32_t reg)
>          return value;
>      }
>      case 0x94: /* CONTROL_NS */
> -        /* We have to handle this here because unprivileged Secure code
> +        /*
> +         * We have to handle this here because unprivileged Secure code
>           * can read the NS CONTROL register.
>           */
>          if (!env->v7m.secure) {
> @@ -12813,7 +12873,8 @@ uint32_t HELPER(v7m_mrs)(CPUARMState *env, uint32_t reg)
>              return env->v7m.faultmask[M_REG_NS];
>          case 0x98: /* SP_NS */
>          {
> -            /* This gives the non-secure SP selected based on whether we're
> +            /*
> +             * This gives the non-secure SP selected based on whether we're
>               * currently in handler mode or not, using the NS CONTROL.SPSEL.
>               */
>              bool spsel = env->v7m.control[M_REG_NS] & R_V7M_CONTROL_SPSEL_MASK;
> @@ -12864,7 +12925,8 @@ uint32_t HELPER(v7m_mrs)(CPUARMState *env, uint32_t reg)
>
>  void HELPER(v7m_msr)(CPUARMState *env, uint32_t maskreg, uint32_t val)
>  {
> -    /* We're passed bits [11..0] of the instruction; extract
> +    /*
> +     * 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.
> @@ -12950,7 +13012,8 @@ void HELPER(v7m_msr)(CPUARMState *env, uint32_t maskreg, uint32_t val)
>              return;
>          case 0x98: /* SP_NS */
>          {
> -            /* This gives the non-secure SP selected based on whether we're
> +            /*
> +             * This gives the non-secure SP selected based on whether we're
>               * currently in handler mode or not, using the NS CONTROL.SPSEL.
>               */
>              bool spsel = env->v7m.control[M_REG_NS] & R_V7M_CONTROL_SPSEL_MASK;
> @@ -13111,7 +13174,8 @@ uint32_t HELPER(v7m_tt)(CPUARMState *env, uint32_t addr, uint32_t op)
>      bool targetsec = env->v7m.secure;
>      bool is_subpage;
>
> -    /* Work out what the security state and privilege level we're
> +    /*
> +     * Work out what the security state and privilege level we're
>       * interested in is...
>       */
>      if (alt) {
> @@ -13128,12 +13192,14 @@ uint32_t HELPER(v7m_tt)(CPUARMState *env, uint32_t addr, uint32_t op)
>      /* ...and then figure out which MMU index this is */
>      mmu_idx = arm_v7m_mmu_idx_for_secstate_and_priv(env, targetsec, targetpriv);
>
> -    /* We know that the MPU and SAU don't care about the access type
> +    /*
> +     * 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
> +    /*
> +     * MPU region info only available for privileged or if
>       * inspecting the other MPU state.
>       */
>      if (arm_current_el(env) != 0 || alt) {
> @@ -13238,7 +13304,8 @@ bool arm_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
>
>  void HELPER(dc_zva)(CPUARMState *env, uint64_t vaddr_in)
>  {
> -    /* Implement DC ZVA, which zeroes a fixed-length block of memory.
> +    /*
> +     * Implement DC ZVA, which zeroes a fixed-length block of memory.
>       * Note that we do not implement the (architecturally mandated)
>       * alignment fault for attempts to use this on Device memory
>       * (which matches the usual QEMU behaviour of not implementing either
> @@ -13251,7 +13318,8 @@ void HELPER(dc_zva)(CPUARMState *env, uint64_t vaddr_in)
>
>  #ifndef CONFIG_USER_ONLY
>      {
> -        /* Slightly awkwardly, QEMU's TARGET_PAGE_SIZE may be less than
> +        /*
> +         * Slightly awkwardly, QEMU's TARGET_PAGE_SIZE may be less than
>           * the block size so we might have to do more than one TLB lookup.
>           * We know that in fact for any v8 CPU the page size is at least 4K
>           * and the block size must be 2K or less, but TARGET_PAGE_SIZE is only
> @@ -13278,7 +13346,8 @@ void HELPER(dc_zva)(CPUARMState *env, uint64_t vaddr_in)
>                  }
>              }
>              if (i == maxidx) {
> -                /* If it's all in the TLB it's fair game for just writing to;
> +                /*
> +                 * If it's all in the TLB it's fair game for just writing to;
>                   * we know we don't need to update dirty status, etc.
>                   */
>                  for (i = 0; i < maxidx - 1; i++) {
> @@ -13287,7 +13356,8 @@ void HELPER(dc_zva)(CPUARMState *env, uint64_t vaddr_in)
>                  memset(hostaddr[i], 0, blocklen - (i * TARGET_PAGE_SIZE));
>                  return;
>              }
> -            /* OK, try a store and see if we can populate the tlb. This
> +            /*
> +             * OK, try a store and see if we can populate the tlb. This
>               * might cause an exception if the memory isn't writable,
>               * in which case we will longjmp out of here. We must for
>               * this purpose use the actual register value passed to us
> @@ -13303,7 +13373,8 @@ void HELPER(dc_zva)(CPUARMState *env, uint64_t vaddr_in)
>              }
>          }
>
> -        /* Slow path (probably attempt to do this to an I/O device or
> +        /*
> +         * Slow path (probably attempt to do this to an I/O device or
>           * similar, or clearing of a block of code we have translations
>           * cached for). Just do a series of byte writes as the architecture
>           * demands. It's not worth trying to use a cpu_physical_memory_map(),
> diff --git a/target/arm/op_helper.c b/target/arm/op_helper.c
> index 4db254876d..db4254a67b 100644
> --- a/target/arm/op_helper.c
> +++ b/target/arm/op_helper.c
> @@ -970,7 +970,8 @@ static bool linked_bp_matches(ARMCPU *cpu, int lbn)
>      int bt;
>      uint32_t contextidr;
>
> -    /* Links to unimplemented or non-context aware breakpoints are
> +    /*
> +     * 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<n>_EL1.LBN must indicate that breakpoint).
> @@ -989,7 +990,8 @@ static bool linked_bp_matches(ARMCPU *cpu, int lbn)
>
>      bt = extract64(bcr, 20, 4);
>
> -    /* We match the whole register even if this is AArch32 using the
> +    /*
> +     * We match the whole register even if this is AArch32 using the
>       * short descriptor format (in which case it holds both PROCID and ASID),
>       * since we don't implement the optional v7 context ID masking.
>       */
> @@ -1006,7 +1008,8 @@ static bool linked_bp_matches(ARMCPU *cpu, int lbn)
>      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
> +        /*
> +         * Links to Unlinked context breakpoints must generate no
>           * events; we choose to do the same for reserved values too.
>           */
>          return false;
> @@ -1020,7 +1023,8 @@ static bool bp_wp_matches(ARMCPU *cpu, int n, bool is_wp)
>      CPUARMState *env = &cpu->env;
>      uint64_t cr;
>      int pac, hmc, ssc, wt, lbn;
> -    /* Note that for watchpoints the check is against the CPU security
> +    /*
> +     * 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 = arm_is_secure(env);
> @@ -1034,7 +1038,8 @@ static bool bp_wp_matches(ARMCPU *cpu, int n, bool is_wp)
>          }
>          cr = env->cp15.dbgwcr[n];
>          if (wp->hitattrs.user) {
> -            /* The LDRT/STRT/LDT/STT "unprivileged access" instructions should
> +            /*
> +             * The LDRT/STRT/LDT/STT "unprivileged access" instructions should
>               * match watchpoints as if they were accesses done at EL0, even if
>               * the CPU is at EL1 or higher.
>               */
> @@ -1048,7 +1053,8 @@ static bool bp_wp_matches(ARMCPU *cpu, int n, bool is_wp)
>          }
>          cr = env->cp15.dbgbcr[n];
>      }
> -    /* The WATCHPOINT_HIT flag guarantees us that the watchpoint is
> +    /*
> +     * 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
> @@ -1116,7 +1122,8 @@ static bool check_watchpoints(ARMCPU *cpu)
>      CPUARMState *env = &cpu->env;
>      int n;
>
> -    /* If watchpoints are disabled globally or we can't take debug
> +    /*
> +     * 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) == 0
> @@ -1164,7 +1171,8 @@ void HELPER(check_breakpoints)(CPUARMState *env)
>
>  bool arm_debug_check_watchpoint(CPUState *cs, CPUWatchpoint *wp)
>  {
> -    /* Called by core code when a CPU watchpoint fires; need to check if this
> +    /*
> +     * Called by core code when a CPU watchpoint fires; need to check if this
>       * is also an architectural watchpoint match.
>       */
>      ARMCPU *cpu = ARM_CPU(cs);
> @@ -1177,7 +1185,8 @@ vaddr arm_adjust_watchpoint_address(CPUState *cs, vaddr addr, int len)
>      ARMCPU *cpu = ARM_CPU(cs);
>      CPUARMState *env = &cpu->env;
>
> -    /* In BE32 system mode, target memory is stored byteswapped (on a
> +    /*
> +     * 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.


--
Alex Bennée


^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [Qemu-devel] [PATCH v2 08/23] target/arm: Move all v7m insn helpers into their own file
  2019-06-15 15:43 ` [Qemu-devel] [PATCH v2 08/23] target/arm: Move all v7m insn helpers into their own file Philippe Mathieu-Daudé
@ 2019-06-17 11:42   ` Alex Bennée
  2019-06-17 12:12     ` Philippe Mathieu-Daudé
  0 siblings, 1 reply; 51+ messages in thread
From: Alex Bennée @ 2019-06-17 11:42 UTC (permalink / raw)
  To: qemu-devel
  Cc: Peter Maydell, qemu-arm, Philippe Mathieu-Daudé, Samuel Ortiz


Philippe Mathieu-Daudé <philmd@redhat.com> writes:

> From: Samuel Ortiz <sameo@linux.intel.com>
>
> In preparation for supporting TCG disablement on ARM, we move most
> of TCG related v7m helpers and APIs into their own file.
>
> Signed-off-by: Samuel Ortiz <sameo@linux.intel.com>
> [PMD: Patch rewritten]
> Signed-off-by: Philippe Mathieu-Daudé <philmd@redhat.com>
> ---
> Is there a way to not use $CONFIG_USER_ONLY?

Is this because the CONFIG_ARM_V7M symbol only appears for softmmu
targets but we still want vXm -cpu's for user mode?

>
>  target/arm/Makefile.objs |   1 +
>  target/arm/helper.c      | 633 -------------------------------------
>  target/arm/v7m_helper.c  | 654 +++++++++++++++++++++++++++++++++++++++
>  3 files changed, 655 insertions(+), 633 deletions(-)
>  create mode 100644 target/arm/v7m_helper.c
>
> diff --git a/target/arm/Makefile.objs b/target/arm/Makefile.objs
> index 72b42f825f..5f3f965cc6 100644
> --- a/target/arm/Makefile.objs
> +++ b/target/arm/Makefile.objs
> @@ -35,6 +35,7 @@ obj-y += translate.o op_helper.o
>  obj-y += crypto_helper.o
>  obj-y += iwmmxt_helper.o vec_helper.o
>  obj-y += neon_helper.o vfp_helper.o
> +obj-$(call lor,$(CONFIG_USER_ONLY),$(CONFIG_ARM_V7M)) += v7m_helper.o
>
>  obj-$(TARGET_AARCH64) += translate-a64.o helper-a64.o
>  obj-$(TARGET_AARCH64) += translate-sve.o sve_helper.o
> diff --git a/target/arm/helper.c b/target/arm/helper.c
> index a1e74cc471..a829086c6d 100644
> --- a/target/arm/helper.c
> +++ b/target/arm/helper.c
> @@ -20,7 +20,6 @@
>  #include "qemu/crc32c.h"
>  #include "qemu/qemu-print.h"
>  #include "exec/exec-all.h"
> -#include "exec/cpu_ldst.h"
>  #include "arm_ldst.h"
>  #include <zlib.h> /* For crc32 */
>  #include "hw/semihosting/semihost.h"
> @@ -7456,75 +7455,6 @@ uint32_t HELPER(rbit)(uint32_t x)
>
>  #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 = env_archcpu(env);
> -
> -    cpu_abort(CPU(cpu), "v7m_msr %d\n", reg);
> -}
> -
> -uint32_t HELPER(v7m_mrs)(CPUARMState *env, uint32_t reg)
> -{
> -    ARMCPU *cpu = 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;
> -}
> -
>  void switch_mode(CPUARMState *env, int mode)
>  {
>      ARMCPU *cpu = env_archcpu(env);
> @@ -8048,109 +7978,6 @@ void switch_v7m_security_state(CPUARMState *env, bool new_secstate)
>      }
>  }
>
> -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 = FNC_RETURN_MIN_MAGIC;
> -    } else {
> -        /* EXC_RETURN magic only */
> -        min_magic = EXC_RETURN_MIN_MAGIC;
> -    }
> -
> -    if (dest >= 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 complete"
> -         * event (compare gen_bx_excret_final_code()).
> -         */
> -        env->regs[15] = dest & ~1;
> -        env->thumb = 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] &= ~R_V7M_CONTROL_SFPA_MASK;
> -    }
> -    switch_v7m_security_state(env, dest & 1);
> -    env->thumb = 1;
> -    env->regs[15] = 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 = env->regs[15] | 1;
> -    uint32_t sp = 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] = nextinst;
> -        env->thumb = 1;
> -        env->regs[15] = 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 = env->v7m.exception;
> -    if (env->v7m.control[M_REG_S] & R_V7M_CONTROL_SFPA_MASK) {
> -        saved_psr |= 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] = sp;
> -    env->regs[14] = 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] &= ~R_V7M_CONTROL_SFPA_MASK;
> -    switch_v7m_security_state(env, 0);
> -    env->thumb = 1;
> -    env->regs[15] = dest;
> -}
> -
>  static uint32_t *get_v7m_sp_ptr(CPUARMState *env, bool secure, bool threadmode,
>                                  bool spsel)
>  {
> @@ -12760,466 +12587,6 @@ hwaddr arm_cpu_get_phys_page_attrs_debug(CPUState *cs, vaddr addr,
>      return phys_addr;
>  }
>
> -uint32_t HELPER(v7m_mrs)(CPUARMState *env, uint32_t reg)
> -{
> -    uint32_t mask;
> -    unsigned el = arm_current_el(env);
> -
> -    /* First handle registers which unprivileged can read */
> -
> -    switch (reg) {
> -    case 0 ... 7: /* xPSR sub-fields */
> -        mask = 0;
> -        if ((reg & 1) && el) {
> -            mask |= XPSR_EXCP; /* IPSR (unpriv. reads as zero) */
> -        }
> -        if (!(reg & 4)) {
> -            mask |= XPSR_NZCV | XPSR_Q; /* APSR */
> -            if (arm_feature(env, ARM_FEATURE_THUMB_DSP)) {
> -                mask |= XPSR_GE;
> -            }
> -        }
> -        /* EPSR reads as zero */
> -        return xpsr_read(env) & mask;
> -        break;
> -    case 20: /* CONTROL */
> -    {
> -        uint32_t value = 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 |= 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 == 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.SPSEL.
> -             */
> -            bool spsel = env->v7m.control[M_REG_NS] & R_V7M_CONTROL_SPSEL_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 = extract32(maskreg, 8, 4);
> -    uint32_t reg = extract32(maskreg, 0, 8);
> -    int cur_el = arm_current_el(env);
> -
> -    if (cur_el == 0 && reg > 7 && reg != 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 = val;
> -            return;
> -        case 0x89: /* PSP_NS */
> -            if (!env->v7m.secure) {
> -                return;
> -            }
> -            env->v7m.other_ss_psp = val;
> -            return;
> -        case 0x8a: /* MSPLIM_NS */
> -            if (!env->v7m.secure) {
> -                return;
> -            }
> -            env->v7m.msplim[M_REG_NS] = val & ~7;
> -            return;
> -        case 0x8b: /* PSPLIM_NS */
> -            if (!env->v7m.secure) {
> -                return;
> -            }
> -            env->v7m.psplim[M_REG_NS] = val & ~7;
> -            return;
> -        case 0x90: /* PRIMASK_NS */
> -            if (!env->v7m.secure) {
> -                return;
> -            }
> -            env->v7m.primask[M_REG_NS] = 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] = 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] = 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] &= ~R_V7M_CONTROL_NPRIV_MASK;
> -                env->v7m.control[M_REG_NS] |= val & R_V7M_CONTROL_NPRIV_MASK;
> -            }
> -            /*
> -             * SFPA is RAZ/WI from NS. FPCA is RO if NSACR.CP10 == 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] &= ~R_V7M_CONTROL_FPCA_MASK;
> -                env->v7m.control[M_REG_S] |= val & R_V7M_CONTROL_FPCA_MASK;
> -            }
> -            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.SPSEL.
> -             */
> -            bool spsel = env->v7m.control[M_REG_NS] & R_V7M_CONTROL_SPSEL_MASK;
> -            bool is_psp = !arm_v7m_is_handler_mode(env) && spsel;
> -            uint32_t limit;
> -
> -            if (!env->v7m.secure) {
> -                return;
> -            }
> -
> -            limit = is_psp ? env->v7m.psplim[false] : env->v7m.msplim[false];
> -
> -            if (val < limit) {
> -                CPUState *cs = env_cpu(env);
> -
> -                cpu_restore_state(cs, GETPC(), true);
> -                raise_exception(env, EXCP_STKOF, 0, 1);
> -            }
> -
> -            if (is_psp) {
> -                env->v7m.other_ss_psp = val;
> -            } else {
> -                env->v7m.other_ss_msp = val;
> -            }
> -            return;
> -        }
> -        default:
> -            break;
> -        }
> -    }
> -
> -    switch (reg) {
> -    case 0 ... 7: /* xPSR sub-fields */
> -        /* only APSR is actually writable */
> -        if (!(reg & 4)) {
> -            uint32_t apsrmask = 0;
> -
> -            if (mask & 8) {
> -                apsrmask |= XPSR_NZCV | XPSR_Q;
> -            }
> -            if ((mask & 4) && arm_feature(env, ARM_FEATURE_THUMB_DSP)) {
> -                apsrmask |= XPSR_GE;
> -            }
> -            xpsr_write(env, val, apsrmask);
> -        }
> -        break;
> -    case 8: /* MSP */
> -        if (v7m_using_psp(env)) {
> -            env->v7m.other_sp = val;
> -        } else {
> -            env->regs[13] = val;
> -        }
> -        break;
> -    case 9: /* PSP */
> -        if (v7m_using_psp(env)) {
> -            env->regs[13] = val;
> -        } else {
> -            env->v7m.other_sp = val;
> -        }
> -        break;
> -    case 10: /* MSPLIM */
> -        if (!arm_feature(env, ARM_FEATURE_V8)) {
> -            goto bad_reg;
> -        }
> -        env->v7m.msplim[env->v7m.secure] = val & ~7;
> -        break;
> -    case 11: /* PSPLIM */
> -        if (!arm_feature(env, ARM_FEATURE_V8)) {
> -            goto bad_reg;
> -        }
> -        env->v7m.psplim[env->v7m.secure] = val & ~7;
> -        break;
> -    case 16: /* PRIMASK */
> -        env->v7m.primask[env->v7m.secure] = val & 1;
> -        break;
> -    case 17: /* BASEPRI */
> -        if (!arm_feature(env, ARM_FEATURE_M_MAIN)) {
> -            goto bad_reg;
> -        }
> -        env->v7m.basepri[env->v7m.secure] = val & 0xff;
> -        break;
> -    case 18: /* BASEPRI_MAX */
> -        if (!arm_feature(env, ARM_FEATURE_M_MAIN)) {
> -            goto bad_reg;
> -        }
> -        val &= 0xff;
> -        if (val != 0 && (val < env->v7m.basepri[env->v7m.secure]
> -                         || env->v7m.basepri[env->v7m.secure] == 0)) {
> -            env->v7m.basepri[env->v7m.secure] = val;
> -        }
> -        break;
> -    case 19: /* FAULTMASK */
> -        if (!arm_feature(env, ARM_FEATURE_M_MAIN)) {
> -            goto bad_reg;
> -        }
> -        env->v7m.faultmask[env->v7m.secure] = 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) != 0);
> -        }
> -        if (cur_el > 0 && arm_feature(env, ARM_FEATURE_M_MAIN)) {
> -            env->v7m.control[env->v7m.secure] &= ~R_V7M_CONTROL_NPRIV_MASK;
> -            env->v7m.control[env->v7m.secure] |= val & R_V7M_CONTROL_NPRIV_MASK;
> -        }
> -        if (arm_feature(env, ARM_FEATURE_VFP)) {
> -            /*
> -             * SFPA is RAZ/WI from NS or if no FPU.
> -             * FPCA is RO if NSACR.CP10 == 0, RES0 if the FPU is not present.
> -             * Both are stored in the S bank.
> -             */
> -            if (env->v7m.secure) {
> -                env->v7m.control[M_REG_S] &= ~R_V7M_CONTROL_SFPA_MASK;
> -                env->v7m.control[M_REG_S] |= val & R_V7M_CONTROL_SFPA_MASK;
> -            }
> -            if (cur_el > 0 &&
> -                (env->v7m.secure || !arm_feature(env, ARM_FEATURE_M_SECURITY) ||
> -                 extract32(env->v7m.nsacr, 10, 1))) {
> -                env->v7m.control[M_REG_S] &= ~R_V7M_CONTROL_FPCA_MASK;
> -                env->v7m.control[M_REG_S] |= val & R_V7M_CONTROL_FPCA_MASK;
> -            }
> -        }
> -        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 = op & 1;
> -    bool alt = op & 2;
> -    V8M_SAttributes sattrs = {};
> -    uint32_t tt_resp;
> -    bool r, rw, nsr, nsrw, mrvalid;
> -    int prot;
> -    ARMMMUFaultInfo fi = {};
> -    MemTxAttrs attrs = {};
> -    hwaddr phys_addr;
> -    ARMMMUIdx mmu_idx;
> -    uint32_t mregion;
> -    bool targetpriv;
> -    bool targetsec = env->v7m.secure;
> -    bool is_subpage;
> -
> -    /*
> -     * Work out what the security state and privilege level we're
> -     * interested in is...
> -     */
> -    if (alt) {
> -        targetsec = !targetsec;
> -    }
> -
> -    if (forceunpriv) {
> -        targetpriv = false;
> -    } else {
> -        targetpriv = 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 = arm_v7m_mmu_idx_for_secstate_and_priv(env, targetsec, targetpriv);
> -
> -    /*
> -     * 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) != 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 == -1) {
> -            mrvalid = false;
> -            mregion = 0;
> -        } else {
> -            mrvalid = true;
> -        }
> -        r = prot & PAGE_READ;
> -        rw = prot & PAGE_WRITE;
> -    } else {
> -        r = false;
> -        rw = false;
> -        mrvalid = false;
> -        mregion = 0;
> -    }
> -
> -    if (env->v7m.secure) {
> -        v8m_security_lookup(env, addr, MMU_DATA_LOAD, mmu_idx, &sattrs);
> -        nsr = sattrs.ns && r;
> -        nsrw = sattrs.ns && rw;
> -    } else {
> -        sattrs.ns = true;
> -        nsr = false;
> -        nsrw = false;
> -    }
> -
> -    tt_resp = (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
>
>  bool arm_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
> diff --git a/target/arm/v7m_helper.c b/target/arm/v7m_helper.c
> new file mode 100644
> index 0000000000..321154966e
> --- /dev/null
> +++ b/target/arm/v7m_helper.c
> @@ -0,0 +1,654 @@
> +/*
> + * ARM v7-M 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 "sysemu/sysemu.h"
> +#include "cpu.h"
> +#include "internals.h"
> +#include "exec/helper-proto.h"
> +#include "exec/exec-all.h"
> +#include "arm_ldst.h"
> +#include "hw/semihosting/semihost.h"
> +#include "fpu/softfloat.h"
> +
> +#if defined(CONFIG_USER_ONLY)
> +
> +/* These should probably raise undefined insn exceptions.  */
> +void HELPER(v7m_msr)(CPUARMState *env, uint32_t reg, uint32_t val)
> +{
> +    ARMCPU *cpu = env_archcpu(env);
> +
> +    cpu_abort(CPU(cpu), "v7m_msr %d\n", reg);
> +}
> +
> +uint32_t HELPER(v7m_mrs)(CPUARMState *env, uint32_t reg)
> +{
> +    ARMCPU *cpu = 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
> +
> +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 = FNC_RETURN_MIN_MAGIC;
> +    } else {
> +        /* EXC_RETURN magic only */
> +        min_magic = EXC_RETURN_MIN_MAGIC;
> +    }
> +
> +    if (dest >= 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 complete"
> +         * event (compare gen_bx_excret_final_code()).
> +         */
> +        env->regs[15] = dest & ~1;
> +        env->thumb = 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] &= ~R_V7M_CONTROL_SFPA_MASK;
> +    }
> +    switch_v7m_security_state(env, dest & 1);
> +    env->thumb = 1;
> +    env->regs[15] = 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 = env->regs[15] | 1;
> +    uint32_t sp = 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] = nextinst;
> +        env->thumb = 1;
> +        env->regs[15] = 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 = env->v7m.exception;
> +    if (env->v7m.control[M_REG_S] & R_V7M_CONTROL_SFPA_MASK) {
> +        saved_psr |= 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] = sp;
> +    env->regs[14] = 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] &= ~R_V7M_CONTROL_SFPA_MASK;
> +    switch_v7m_security_state(env, 0);
> +    env->thumb = 1;
> +    env->regs[15] = dest;
> +}
> +
> +uint32_t HELPER(v7m_mrs)(CPUARMState *env, uint32_t reg)
> +{
> +    uint32_t mask;
> +    unsigned el = arm_current_el(env);
> +
> +    /* First handle registers which unprivileged can read */
> +
> +    switch (reg) {
> +    case 0 ... 7: /* xPSR sub-fields */
> +        mask = 0;
> +        if ((reg & 1) && el) {
> +            mask |= XPSR_EXCP; /* IPSR (unpriv. reads as zero) */
> +        }
> +        if (!(reg & 4)) {
> +            mask |= XPSR_NZCV | XPSR_Q; /* APSR */
> +            if (arm_feature(env, ARM_FEATURE_THUMB_DSP)) {
> +                mask |= XPSR_GE;
> +            }
> +        }
> +        /* EPSR reads as zero */
> +        return xpsr_read(env) & mask;
> +        break;
> +    case 20: /* CONTROL */
> +    {
> +        uint32_t value = 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 |= 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 == 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.SPSEL.
> +             */
> +            bool spsel = env->v7m.control[M_REG_NS] & R_V7M_CONTROL_SPSEL_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 = extract32(maskreg, 8, 4);
> +    uint32_t reg = extract32(maskreg, 0, 8);
> +    int cur_el = arm_current_el(env);
> +
> +    if (cur_el == 0 && reg > 7 && reg != 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 = val;
> +            return;
> +        case 0x89: /* PSP_NS */
> +            if (!env->v7m.secure) {
> +                return;
> +            }
> +            env->v7m.other_ss_psp = val;
> +            return;
> +        case 0x8a: /* MSPLIM_NS */
> +            if (!env->v7m.secure) {
> +                return;
> +            }
> +            env->v7m.msplim[M_REG_NS] = val & ~7;
> +            return;
> +        case 0x8b: /* PSPLIM_NS */
> +            if (!env->v7m.secure) {
> +                return;
> +            }
> +            env->v7m.psplim[M_REG_NS] = val & ~7;
> +            return;
> +        case 0x90: /* PRIMASK_NS */
> +            if (!env->v7m.secure) {
> +                return;
> +            }
> +            env->v7m.primask[M_REG_NS] = 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] = 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] = 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] &= ~R_V7M_CONTROL_NPRIV_MASK;
> +                env->v7m.control[M_REG_NS] |= val & R_V7M_CONTROL_NPRIV_MASK;
> +            }
> +            /*
> +             * SFPA is RAZ/WI from NS. FPCA is RO if NSACR.CP10 == 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] &= ~R_V7M_CONTROL_FPCA_MASK;
> +                env->v7m.control[M_REG_S] |= val & R_V7M_CONTROL_FPCA_MASK;
> +            }
> +            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.SPSEL.
> +             */
> +            bool spsel = env->v7m.control[M_REG_NS] & R_V7M_CONTROL_SPSEL_MASK;
> +            bool is_psp = !arm_v7m_is_handler_mode(env) && spsel;
> +            uint32_t limit;
> +
> +            if (!env->v7m.secure) {
> +                return;
> +            }
> +
> +            limit = is_psp ? env->v7m.psplim[false] : env->v7m.msplim[false];
> +
> +            if (val < limit) {
> +                CPUState *cs = env_cpu(env);
> +
> +                cpu_restore_state(cs, GETPC(), true);
> +                raise_exception(env, EXCP_STKOF, 0, 1);
> +            }
> +
> +            if (is_psp) {
> +                env->v7m.other_ss_psp = val;
> +            } else {
> +                env->v7m.other_ss_msp = val;
> +            }
> +            return;
> +        }
> +        default:
> +            break;
> +        }
> +    }
> +
> +    switch (reg) {
> +    case 0 ... 7: /* xPSR sub-fields */
> +        /* only APSR is actually writable */
> +        if (!(reg & 4)) {
> +            uint32_t apsrmask = 0;
> +
> +            if (mask & 8) {
> +                apsrmask |= XPSR_NZCV | XPSR_Q;
> +            }
> +            if ((mask & 4) && arm_feature(env, ARM_FEATURE_THUMB_DSP)) {
> +                apsrmask |= XPSR_GE;
> +            }
> +            xpsr_write(env, val, apsrmask);
> +        }
> +        break;
> +    case 8: /* MSP */
> +        if (v7m_using_psp(env)) {
> +            env->v7m.other_sp = val;
> +        } else {
> +            env->regs[13] = val;
> +        }
> +        break;
> +    case 9: /* PSP */
> +        if (v7m_using_psp(env)) {
> +            env->regs[13] = val;
> +        } else {
> +            env->v7m.other_sp = val;
> +        }
> +        break;
> +    case 10: /* MSPLIM */
> +        if (!arm_feature(env, ARM_FEATURE_V8)) {
> +            goto bad_reg;
> +        }
> +        env->v7m.msplim[env->v7m.secure] = val & ~7;
> +        break;
> +    case 11: /* PSPLIM */
> +        if (!arm_feature(env, ARM_FEATURE_V8)) {
> +            goto bad_reg;
> +        }
> +        env->v7m.psplim[env->v7m.secure] = val & ~7;
> +        break;
> +    case 16: /* PRIMASK */
> +        env->v7m.primask[env->v7m.secure] = val & 1;
> +        break;
> +    case 17: /* BASEPRI */
> +        if (!arm_feature(env, ARM_FEATURE_M_MAIN)) {
> +            goto bad_reg;
> +        }
> +        env->v7m.basepri[env->v7m.secure] = val & 0xff;
> +        break;
> +    case 18: /* BASEPRI_MAX */
> +        if (!arm_feature(env, ARM_FEATURE_M_MAIN)) {
> +            goto bad_reg;
> +        }
> +        val &= 0xff;
> +        if (val != 0 && (val < env->v7m.basepri[env->v7m.secure]
> +                         || env->v7m.basepri[env->v7m.secure] == 0)) {
> +            env->v7m.basepri[env->v7m.secure] = val;
> +        }
> +        break;
> +    case 19: /* FAULTMASK */
> +        if (!arm_feature(env, ARM_FEATURE_M_MAIN)) {
> +            goto bad_reg;
> +        }
> +        env->v7m.faultmask[env->v7m.secure] = 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) != 0);
> +        }
> +        if (cur_el > 0 && arm_feature(env, ARM_FEATURE_M_MAIN)) {
> +            env->v7m.control[env->v7m.secure] &= ~R_V7M_CONTROL_NPRIV_MASK;
> +            env->v7m.control[env->v7m.secure] |= val & R_V7M_CONTROL_NPRIV_MASK;
> +        }
> +        if (arm_feature(env, ARM_FEATURE_VFP)) {
> +            /*
> +             * SFPA is RAZ/WI from NS or if no FPU.
> +             * FPCA is RO if NSACR.CP10 == 0, RES0 if the FPU is not present.
> +             * Both are stored in the S bank.
> +             */
> +            if (env->v7m.secure) {
> +                env->v7m.control[M_REG_S] &= ~R_V7M_CONTROL_SFPA_MASK;
> +                env->v7m.control[M_REG_S] |= val & R_V7M_CONTROL_SFPA_MASK;
> +            }
> +            if (cur_el > 0 &&
> +                (env->v7m.secure || !arm_feature(env, ARM_FEATURE_M_SECURITY) ||
> +                 extract32(env->v7m.nsacr, 10, 1))) {
> +                env->v7m.control[M_REG_S] &= ~R_V7M_CONTROL_FPCA_MASK;
> +                env->v7m.control[M_REG_S] |= val & R_V7M_CONTROL_FPCA_MASK;
> +            }
> +        }
> +        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 = op & 1;
> +    bool alt = op & 2;
> +    V8M_SAttributes sattrs = {};
> +    uint32_t tt_resp;
> +    bool r, rw, nsr, nsrw, mrvalid;
> +    int prot;
> +    ARMMMUFaultInfo fi = {};
> +    MemTxAttrs attrs = {};
> +    hwaddr phys_addr;
> +    ARMMMUIdx mmu_idx;
> +    uint32_t mregion;
> +    bool targetpriv;
> +    bool targetsec = env->v7m.secure;
> +    bool is_subpage;
> +
> +    /*
> +     * Work out what the security state and privilege level we're
> +     * interested in is...
> +     */
> +    if (alt) {
> +        targetsec = !targetsec;
> +    }
> +
> +    if (forceunpriv) {
> +        targetpriv = false;
> +    } else {
> +        targetpriv = 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 = arm_v7m_mmu_idx_for_secstate_and_priv(env, targetsec, targetpriv);
> +
> +    /*
> +     * 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) != 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 == -1) {
> +            mrvalid = false;
> +            mregion = 0;
> +        } else {
> +            mrvalid = true;
> +        }
> +        r = prot & PAGE_READ;
> +        rw = prot & PAGE_WRITE;
> +    } else {
> +        r = false;
> +        rw = false;
> +        mrvalid = false;
> +        mregion = 0;
> +    }
> +
> +    if (env->v7m.secure) {
> +        v8m_security_lookup(env, addr, MMU_DATA_LOAD, mmu_idx, &sattrs);
> +        nsr = sattrs.ns && r;
> +        nsrw = sattrs.ns && rw;
> +    } else {
> +        sattrs.ns = true;
> +        nsr = false;
> +        nsrw = false;
> +    }
> +
> +    tt_resp = (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 */


--
Alex Bennée


^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [Qemu-devel] [PATCH v2 08/23] target/arm: Move all v7m insn helpers into their own file
  2019-06-17 11:42   ` Alex Bennée
@ 2019-06-17 12:12     ` Philippe Mathieu-Daudé
  0 siblings, 0 replies; 51+ messages in thread
From: Philippe Mathieu-Daudé @ 2019-06-17 12:12 UTC (permalink / raw)
  To: Alex Bennée, qemu-devel
  Cc: Peter Maydell, qemu-arm, Richard Henderson, Samuel Ortiz

On 6/17/19 1:42 PM, Alex Bennée wrote:
> Philippe Mathieu-Daudé <philmd@redhat.com> writes:
> 
>> From: Samuel Ortiz <sameo@linux.intel.com>
>>
>> In preparation for supporting TCG disablement on ARM, we move most
>> of TCG related v7m helpers and APIs into their own file.
>>
>> Signed-off-by: Samuel Ortiz <sameo@linux.intel.com>
>> [PMD: Patch rewritten]
>> Signed-off-by: Philippe Mathieu-Daudé <philmd@redhat.com>
>> ---
>> Is there a way to not use $CONFIG_USER_ONLY?
> 
> Is this because the CONFIG_ARM_V7M symbol only appears for softmmu
> targets but we still want vXm -cpu's for user mode?

No :(

If I use this diff:

-- >8 --
diff --git a/target/arm/helper.h b/target/arm/helper.h
@@ -58,24 +58,26 @@ DEF_HELPER_2(pre_smc, void, env, i32)
 DEF_HELPER_1(check_breakpoints, void, env)

 DEF_HELPER_3(cpsr_write, void, env, i32, i32)
 DEF_HELPER_2(cpsr_write_eret, void, env, i32)
 DEF_HELPER_1(cpsr_read, i32, env)

+#ifndef CONFIG_USER_ONLY
 DEF_HELPER_3(v7m_msr, void, env, i32, i32)
 DEF_HELPER_2(v7m_mrs, i32, env, i32)

 DEF_HELPER_2(v7m_bxns, void, env, i32)
 DEF_HELPER_2(v7m_blxns, void, env, i32)

 DEF_HELPER_3(v7m_tt, i32, env, i32, i32)

 DEF_HELPER_1(v7m_preserve_fp_state, void, env)

 DEF_HELPER_2(v7m_vlstm, void, env, i32)
 DEF_HELPER_2(v7m_vlldm, void, env, i32)
+#endif /* CONFIG_USER_ONLY */

 DEF_HELPER_2(v8m_stackcheck, void, env, i32)
---

I get:

target/arm/translate.c:10607:29: error: nested extern declaration of
‘gen_helper_v7m_mrs’ [-Werror=nested-externs]
target/arm/translate.c: In function ‘disas_thumb_insn’:
target/arm/translate.c:11224:25: error: implicit declaration of function
‘gen_blxns’; did you mean ‘gen_bx’? [-Werror=implicit-function-declaration]
                         gen_blxns(s, rm);
                         ^~~~~~~~~

Because:

static void disas_thumb_insn(DisasContext *s, uint32_t insn)
{
    ...
    switch (insn >> 12) {
    ...
    case 4:
        ...
        if (insn & (1 << 10)) {
            ...
            case 3:
            {
                /* 0b0100_0111_xxxx_xxxx
                 * - branch [and link] exchange thumb register
                 */
                bool link = insn & (1 << 7);

                if (insn & 3) {
                    goto undef;
                }
                if (link) {
                    ARCH(5);
                }
                if ((insn & 4)) {
                    /* BXNS/BLXNS: only exists for v8M with the
                     * security extensions, and always UNDEF if NonSecure.
                     * We don't implement these in the user-only mode
                     * either (in theory you can use them from Secure User
                     * mode but they are too tied in to system emulation.)
                     */
                    if (!s->v8m_secure || IS_USER_ONLY) {
                        goto undef;
                    }
                    if (link) {
                        gen_blxns(s, rm);
                    } else {
                        gen_bxns(s, rm);
                    }
                    break;
                }

Should we add "#ifndef CONFIG_USER_ONLY" all around? I believe we rather
not...

For 'cps' and 'mrs' we have:

                        /* Implemented as NOP in user mode.  */
                        if (IS_USER(s))
                            break;

but not for 'msr'.


^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [Qemu-devel] [Qemu-arm] [NOTFORMERGE PATCH v2 23/23] Missing symbols when building with --disable-tcg
  2019-06-15 15:43 ` [Qemu-devel] [NOTFORMERGE PATCH v2 23/23] Missing symbols when building with --disable-tcg Philippe Mathieu-Daudé
@ 2019-06-17 14:04   ` Alex Bennée
  0 siblings, 0 replies; 51+ messages in thread
From: Alex Bennée @ 2019-06-17 14:04 UTC (permalink / raw)
  To: qemu-arm; +Cc: Peter Maydell, Philippe Mathieu-Daudé, qemu-devel


Philippe Mathieu-Daudé <philmd@redhat.com> writes:

> While it might be normal to disable PSCI on KVM, I doubt the
> VFP helpers are correct ;)
>
> Anyway this allow to link the binary and run a KVM guest.

But also:

/home/alex/lsrc/qemu.git/target/arm/helper.c: In function ‘S1_ptw_translate’:
/home/alex/lsrc/qemu.git/target/arm/helper.c:8794:15: note: parameter passing for argument of type ‘MemTxAttrs’ {aka ‘struct MemTxAttrs’} changed in GCC 9.1
 8794 | static hwaddr S1_ptw_translate(CPUARMState *env, ARMMMUIdx mmu_idx,
      |               ^~~~~~~~~~~~~~~~
  LINK    x86_64-linux-user/qemu-x86_64
  LINK    xtensa-linux-user/qemu-xtensa
/home/alex/lsrc/qemu.git/target/arm/helper.c: In function ‘S1_ptw_translate’:
/home/alex/lsrc/qemu.git/target/arm/helper.c:8794:15: note: parameter passing for argument of type ‘MemTxAttrs’ {aka ‘struct MemTxAttrs’} changed in GCC 9.1
 8794 | static hwaddr S1_ptw_translate(CPUARMState *env, ARMMMUIdx mmu_idx,
      |               ^~~~~~~~~~~~~~~~
  LINK    xtensaeb-linux-user/qemu-xtensaeb
  LINK    arm-linux-user/qemu-arm
  LINK    aarch64-linux-user/qemu-aarch64
  LINK    armeb-linux-user/qemu-armeb
  LINK    aarch64_be-linux-user/qemu-aarch64_be
  LINK    arm-softmmu/qemu-system-arm
  LINK    aarch64-softmmu/qemu-system-aarch64
/usr/lib/gcc/aarch64-unknown-linux-gnu/9.1.0/../../../../aarch64-unknown-linux-gnu/bin/ld: target/arm/kvm-missing.o: in function `arm_is_psci_call':
/home/alex/lsrc/qemu.git/target/arm/kvm-missing.c:17: multiple definition of `arm_is_psci_call'; target/arm/psci.o:/home/alex/lsrc/qemu.git/target/arm/psci.c:36: first defined here
/usr/lib/gcc/aarch64-unknown-linux-gnu/9.1.0/../../../../aarch64-unknown-linux-gnu/bin/ld: target/arm/kvm-missing.o: in function `arm_handle_psci_call':
/home/alex/lsrc/qemu.git/target/arm/kvm-missing.c:20: multiple definition of `arm_handle_psci_call'; target/arm/psci.o:/home/alex/lsrc/qemu.git/target/arm/psci.c:77: first defined here
/usr/lib/gcc/aarch64-unknown-linux-gnu/9.1.0/../../../../aarch64-unknown-linux-gnu/bin/ld: target/arm/vfp_helper.o: in function `vfp_get_fpscr':
/home/alex/lsrc/qemu.git/target/arm/vfp_helper.c:75: multiple definition of `vfp_get_fpscr'; target/arm/kvm-missing.o:/home/alex/lsrc/qemu.git/target/arm/kvm-missing.c:8: first defined here
/usr/lib/gcc/aarch64-unknown-linux-gnu/9.1.0/../../../../aarch64-unknown-linux-gnu/bin/ld: target/arm/vfp_helper.o: in function `vfp_set_fpscr':
/home/alex/lsrc/qemu.git/target/arm/vfp_helper.c:185: multiple definition of `vfp_set_fpscr'; target/arm/kvm-missing.o:/home/alex/lsrc/qemu.git/target/arm/kvm-missing.c:12:
first defined here
collect2: error: ld returned 1 exit status
make[1]: *** [Makefile:204: qemu-system-aarch64] Error 1
make: *** [Makefile:472: subdir-aarch64-softmmu] Error 2

On AArch64 host with TCG enabled....

>
> Tested using:
>
>   $ make pc-bios/edk2-aarch64-code.fd
>   $ dd if=/dev/zero of=flash1.img bs=1M count=64
>   $ aarch64-softmmu/qemu-system-aarch64 \
>     -nographic \
>     -enable-kvm \
>     -M virt,gic-version=3 \
>     -cpu host \
>     \
>     -pflash pc-bios/edk2-aarch64-code.fd \
>     -pflash flash1.img \
>     -drive if=none,file=bionic-server-cloudimg-arm64.img,id=hd0 \
>     -device virtio-blk-device,drive=hd0 \
>     \
>     -netdev type=user,id=net0 \
>     -device virtio-net-device,netdev=net0
>
> Signed-off-by: Philippe Mathieu-Daudé <philmd@redhat.com>
> ---
>  target/arm/Makefile.objs |  1 +
>  target/arm/kvm-missing.c | 22 ++++++++++++++++++++++
>  2 files changed, 23 insertions(+)
>  create mode 100644 target/arm/kvm-missing.c
>
> diff --git a/target/arm/Makefile.objs b/target/arm/Makefile.objs
> index b8aa9c032a..bf1cad2909 100644
> --- a/target/arm/Makefile.objs
> +++ b/target/arm/Makefile.objs
> @@ -6,6 +6,7 @@ obj-$(CONFIG_SOFTMMU) += machine.o arch_dump.o monitor.o arm-powerctl.o
>  obj-$(call land,$(CONFIG_TCG),$(CONFIG_SOFTMMU)) += psci.o
>
>  obj-$(CONFIG_KVM) += kvm.o
> +obj-$(CONFIG_KVM) += kvm-missing.o
>  obj-$(call land,$(CONFIG_KVM),$(call lnot,$(TARGET_AARCH64))) += kvm32.o
>  obj-$(call land,$(CONFIG_KVM),$(TARGET_AARCH64)) += kvm64.o
>  obj-$(call lnot,$(CONFIG_KVM)) += kvm-stub.o
> diff --git a/target/arm/kvm-missing.c b/target/arm/kvm-missing.c
> new file mode 100644
> index 0000000000..0b32cd4e9c
> --- /dev/null
> +++ b/target/arm/kvm-missing.c
> @@ -0,0 +1,22 @@
> +#include "qemu/osdep.h"
> +#include "cpu.h"
> +#include "internals.h"
> +
> +uint32_t vfp_get_fpscr(CPUARMState *env)
> +{
> +    return 0;
> +}
> +
> +void vfp_set_fpscr(CPUARMState *env, uint32_t val)
> +{
> +}
> +
> +bool arm_is_psci_call(ARMCPU *cpu, int excp_type)
> +{
> +    return false;
> +}
> +
> +void arm_handle_psci_call(ARMCPU *cpu)
> +{
> +    abort();
> +}


--
Alex Bennée


^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [Qemu-devel] [RFC PATCH v2 22/23] target/arm: Restrict semi-hosting to TCG
  2019-06-15 15:43 ` [Qemu-devel] [RFC PATCH v2 22/23] target/arm: Restrict semi-hosting to TCG Philippe Mathieu-Daudé
@ 2019-06-17 14:07   ` Alex Bennée
  0 siblings, 0 replies; 51+ messages in thread
From: Alex Bennée @ 2019-06-17 14:07 UTC (permalink / raw)
  To: qemu-devel; +Cc: Peter Maydell, qemu-arm, Philippe Mathieu-Daudé


Philippe Mathieu-Daudé <philmd@redhat.com> writes:

> 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é <philmd@redhat.com>

Reviewed-by: Alex Bennée <alex.bennee@linaro.org>

> ---
>  target/arm/helper.c | 8 +++++++-
>  1 file changed, 7 insertions(+), 1 deletion(-)
>
> diff --git a/target/arm/helper.c b/target/arm/helper.c
> index 8b7ce0561b..a3843a5508 100644
> --- a/target/arm/helper.c
> +++ b/target/arm/helper.c
> @@ -20,7 +20,6 @@
>  #include "qemu/crc32c.h"
>  #include "qemu/qemu-print.h"
>  #include "exec/exec-all.h"
> -#include "arm_ldst.h"
>  #include <zlib.h> /* For crc32 */
>  #include "hw/semihosting/semihost.h"
>  #include "sysemu/cpus.h"
> @@ -30,6 +29,9 @@
>  #include "qapi/qapi-commands-target.h"
>  #include "qapi/error.h"
>  #include "qemu/guest-random.h"
> +#ifdef CONFIG_TCG
> +#include "arm_ldst.h"
> +#endif
>
>  #define ARM_CPU_FREQ 1000000000 /* FIXME: 1 GHz, should be configurable */
>
> @@ -8270,6 +8272,7 @@ static void arm_cpu_do_interrupt_aarch64(CPUState *cs)
>
>  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.
>       */
> @@ -8345,6 +8348,9 @@ static inline bool check_for_semihosting(CPUState *cs)
>          env->regs[0] = do_arm_semihosting(env);
>          return true;
>      }
> +#else
> +    return false;
> +#endif
>  }
>
>  /* Handle a CPU exception for A and R profile CPUs.


--
Alex Bennée


^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [Qemu-devel] [Qemu-arm] [PATCH v2 07/23] target/arm: Declare some function publicly
  2019-06-15 15:43 ` [Qemu-devel] [PATCH v2 07/23] target/arm: Declare some function publicly Philippe Mathieu-Daudé
@ 2019-06-17 14:07   ` Alex Bennée
  0 siblings, 0 replies; 51+ messages in thread
From: Alex Bennée @ 2019-06-17 14:07 UTC (permalink / raw)
  To: qemu-arm; +Cc: Peter Maydell, Philippe Mathieu-Daudé, qemu-devel


Philippe Mathieu-Daudé <philmd@redhat.com> writes:

> In few commits we will split the v7-M functions from this file.
> Some function will be called out of helper.c. Declare them
> in the "internals.h" header.
>
> Signed-off-by: Philippe Mathieu-Daudé <philmd@redhat.com>

Reviewed-by: Alex Bennée <alex.bennee@linaro.org>

> ---
>  target/arm/helper.c    | 69 +++++++++++++-----------------------------
>  target/arm/internals.h | 45 +++++++++++++++++++++++++++
>  2 files changed, 66 insertions(+), 48 deletions(-)
>
> diff --git a/target/arm/helper.c b/target/arm/helper.c
> index 9a3766b759..a1e74cc471 100644
> --- a/target/arm/helper.c
> +++ b/target/arm/helper.c
> @@ -35,17 +35,6 @@
>  #define ARM_CPU_FREQ 1000000000 /* FIXME: 1 GHz, should be configurable */
>
>  #ifndef CONFIG_USER_ONLY
> -/* Cacheability and shareability attributes for a memory access */
> -typedef struct ARMCacheAttrs {
> -    unsigned int attrs:8; /* as in the MAIR register encoding */
> -    unsigned int shareability:2; /* as in the SH field of the VMSAv8-64 PTEs */
> -} ARMCacheAttrs;
> -
> -static bool get_phys_addr(CPUARMState *env, target_ulong address,
> -                          MMUAccessType access_type, ARMMMUIdx mmu_idx,
> -                          hwaddr *phys_ptr, MemTxAttrs *attrs, int *prot,
> -                          target_ulong *page_size,
> -                          ARMMMUFaultInfo *fi, ARMCacheAttrs *cacheattrs);
>
>  static bool get_phys_addr_lpae(CPUARMState *env, target_ulong address,
>                                 MMUAccessType access_type, ARMMMUIdx mmu_idx,
> @@ -53,24 +42,8 @@ static bool get_phys_addr_lpae(CPUARMState *env, target_ulong address,
>                                 target_ulong *page_size_ptr,
>                                 ARMMMUFaultInfo *fi, ARMCacheAttrs *cacheattrs);
>
> -/* Security attributes for an address, as returned by v8m_security_lookup. */
> -typedef struct V8M_SAttributes {
> -    bool subpage; /* true if these attrs don't cover the whole TARGET_PAGE */
> -    bool ns;
> -    bool nsc;
> -    uint8_t sregion;
> -    bool srvalid;
> -    uint8_t iregion;
> -    bool irvalid;
> -} V8M_SAttributes;
> -
> -static void v8m_security_lookup(CPUARMState *env, uint32_t address,
> -                                MMUAccessType access_type, ARMMMUIdx mmu_idx,
> -                                V8M_SAttributes *sattrs);
>  #endif
>
> -static void switch_mode(CPUARMState *env, int mode);
> -
>  static int vfp_gdb_get_reg(CPUARMState *env, uint8_t *buf, int reg)
>  {
>      int nregs;
> @@ -7552,7 +7525,7 @@ uint32_t HELPER(v7m_tt)(CPUARMState *env, uint32_t addr, uint32_t op)
>      return 0;
>  }
>
> -static void switch_mode(CPUARMState *env, int mode)
> +void switch_mode(CPUARMState *env, int mode)
>  {
>      ARMCPU *cpu = env_archcpu(env);
>
> @@ -7574,7 +7547,7 @@ void aarch64_sync_64_to_32(CPUARMState *env)
>
>  #else
>
> -static void switch_mode(CPUARMState *env, int mode)
> +void switch_mode(CPUARMState *env, int mode)
>  {
>      int old_mode;
>      int i;
> @@ -7988,9 +7961,9 @@ void HELPER(v7m_preserve_fp_state)(CPUARMState *env)
>   * 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)
> +void write_v7m_control_spsel_for_secstate(CPUARMState *env,
> +                                          bool new_spsel,
> +                                          bool secstate)
>  {
>      bool old_is_psp = v7m_using_psp(env);
>
> @@ -8015,7 +7988,7 @@ static void write_v7m_control_spsel_for_secstate(CPUARMState *env,
>   * 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)
> +void write_v7m_control_spsel(CPUARMState *env, bool new_spsel)
>  {
>      write_v7m_control_spsel_for_secstate(env, new_spsel, env->v7m.secure);
>  }
> @@ -8041,7 +8014,7 @@ void write_v7m_exception(CPUARMState *env, uint32_t new_exc)
>  }
>
>  /* Switch M profile security state between NS and S */
> -static void switch_v7m_security_state(CPUARMState *env, bool new_secstate)
> +void switch_v7m_security_state(CPUARMState *env, bool new_secstate)
>  {
>      uint32_t new_ss_msp, new_ss_psp;
>
> @@ -9447,7 +9420,7 @@ static bool do_v7m_function_return(ARMCPU *cpu)
>      return true;
>  }
>
> -static void arm_log_exception(int idx)
> +void arm_log_exception(int idx)
>  {
>      if (qemu_loglevel_mask(CPU_LOG_INT)) {
>          const char *exc = NULL;
> @@ -12122,9 +12095,9 @@ static bool v8m_is_sau_exempt(CPUARMState *env,
>          (address >= 0xe00ff000 && address <= 0xe00fffff);
>  }
>
> -static void v8m_security_lookup(CPUARMState *env, uint32_t address,
> -                                MMUAccessType access_type, ARMMMUIdx mmu_idx,
> -                                V8M_SAttributes *sattrs)
> +void v8m_security_lookup(CPUARMState *env, uint32_t address,
> +                         MMUAccessType access_type, ARMMMUIdx mmu_idx,
> +                         V8M_SAttributes *sattrs)
>  {
>      /* Look up the security attributes for this address. Compare the
>       * pseudocode SecurityCheck() function.
> @@ -12229,11 +12202,11 @@ static void v8m_security_lookup(CPUARMState *env, uint32_t address,
>      }
>  }
>
> -static bool pmsav8_mpu_lookup(CPUARMState *env, uint32_t address,
> -                              MMUAccessType access_type, ARMMMUIdx mmu_idx,
> -                              hwaddr *phys_ptr, MemTxAttrs *txattrs,
> -                              int *prot, bool *is_subpage,
> -                              ARMMMUFaultInfo *fi, uint32_t *mregion)
> +bool pmsav8_mpu_lookup(CPUARMState *env, uint32_t address,
> +                       MMUAccessType access_type, ARMMMUIdx mmu_idx,
> +                       hwaddr *phys_ptr, MemTxAttrs *txattrs,
> +                       int *prot, bool *is_subpage,
> +                       ARMMMUFaultInfo *fi, uint32_t *mregion)
>  {
>      /* Perform a PMSAv8 MPU lookup (without also doing the SAU check
>       * that a full phys-to-virt translation does).
> @@ -12633,11 +12606,11 @@ static ARMCacheAttrs combine_cacheattrs(ARMCacheAttrs s1, ARMCacheAttrs s2)
>   * @fi: set to fault info if the translation fails
>   * @cacheattrs: (if non-NULL) set to the cacheability/shareability attributes
>   */
> -static bool get_phys_addr(CPUARMState *env, target_ulong address,
> -                          MMUAccessType access_type, ARMMMUIdx mmu_idx,
> -                          hwaddr *phys_ptr, MemTxAttrs *attrs, int *prot,
> -                          target_ulong *page_size,
> -                          ARMMMUFaultInfo *fi, ARMCacheAttrs *cacheattrs)
> +bool get_phys_addr(CPUARMState *env, target_ulong address,
> +                   MMUAccessType access_type, ARMMMUIdx mmu_idx,
> +                   hwaddr *phys_ptr, MemTxAttrs *attrs, int *prot,
> +                   target_ulong *page_size,
> +                   ARMMMUFaultInfo *fi, ARMCacheAttrs *cacheattrs)
>  {
>      if (mmu_idx == ARMMMUIdx_S12NSE0 || mmu_idx == ARMMMUIdx_S12NSE1) {
>          /* Call ourselves recursively to do the stage 1 and then stage 2
> diff --git a/target/arm/internals.h b/target/arm/internals.h
> index 5a02f458f3..04711b317a 100644
> --- a/target/arm/internals.h
> +++ b/target/arm/internals.h
> @@ -985,4 +985,49 @@ static inline int exception_target_el(CPUARMState *env)
>      return target_el;
>  }
>
> +void arm_log_exception(int idx);
> +
> +/* Cacheability and shareability attributes for a memory access */
> +typedef struct ARMCacheAttrs {
> +    unsigned int attrs:8; /* as in the MAIR register encoding */
> +    unsigned int shareability:2; /* as in the SH field of the VMSAv8-64 PTEs */
> +} ARMCacheAttrs;
> +
> +bool get_phys_addr(CPUARMState *env, target_ulong address,
> +                   MMUAccessType access_type, ARMMMUIdx mmu_idx,
> +                   hwaddr *phys_ptr, MemTxAttrs *attrs, int *prot,
> +                   target_ulong *page_size,
> +                   ARMMMUFaultInfo *fi, ARMCacheAttrs *cacheattrs);
> +
> +/* Security attributes for an address, as returned by v8m_security_lookup. */
> +typedef struct V8M_SAttributes {
> +    bool subpage; /* true if these attrs don't cover the whole TARGET_PAGE */
> +    bool ns;
> +    bool nsc;
> +    uint8_t sregion;
> +    bool srvalid;
> +    uint8_t iregion;
> +    bool irvalid;
> +} V8M_SAttributes;
> +
> +void v8m_security_lookup(CPUARMState *env, uint32_t address,
> +                         MMUAccessType access_type, ARMMMUIdx mmu_idx,
> +                         V8M_SAttributes *sattrs);
> +
> +void switch_mode(CPUARMState *, int);
> +
> +bool pmsav8_mpu_lookup(CPUARMState *env, uint32_t address,
> +                       MMUAccessType access_type, ARMMMUIdx mmu_idx,
> +                       hwaddr *phys_ptr, MemTxAttrs *txattrs,
> +                       int *prot, bool *is_subpage,
> +                       ARMMMUFaultInfo *fi, uint32_t *mregion);
> +
> +void write_v7m_control_spsel_for_secstate(CPUARMState *env,
> +                                          bool new_spsel,
> +                                          bool secstate);
> +
> +void write_v7m_control_spsel(CPUARMState *env, bool new_spsel);
> +
> +void switch_v7m_security_state(CPUARMState *env, bool new_secstate);
> +
>  #endif


--
Alex Bennée


^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [Qemu-devel] [Qemu-arm] [PATCH v2 09/23] target/arm: Move code around
  2019-06-15 15:43 ` [Qemu-devel] [PATCH v2 09/23] target/arm: Move code around Philippe Mathieu-Daudé
@ 2019-06-17 14:07   ` Alex Bennée
  0 siblings, 0 replies; 51+ messages in thread
From: Alex Bennée @ 2019-06-17 14:07 UTC (permalink / raw)
  To: qemu-arm; +Cc: Peter Maydell, Philippe Mathieu-Daudé, qemu-devel


Philippe Mathieu-Daudé <philmd@redhat.com> writes:

> To ease the review of the next commit, move the
> write_v7m_exception() function around.
>
> Signed-off-by: Philippe Mathieu-Daudé <philmd@redhat.com>

Reviewed-by: Alex Bennée <alex.bennee@linaro.org>

> ---
>  target/arm/helper.c | 40 ++++++++++++++++++++--------------------
>  1 file changed, 20 insertions(+), 20 deletions(-)
>
> diff --git a/target/arm/helper.c b/target/arm/helper.c
> index a829086c6d..b4fd9b42d7 100644
> --- a/target/arm/helper.c
> +++ b/target/arm/helper.c
> @@ -7923,26 +7923,6 @@ 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 pointer.
> -     */
> -    bool new_is_psp, old_is_psp = v7m_using_psp(env);
> -    uint32_t tmp;
> -
> -    env->v7m.exception = new_exc;
> -
> -    new_is_psp = v7m_using_psp(env);
> -
> -    if (old_is_psp != new_is_psp) {
> -        tmp = env->v7m.other_sp;
> -        env->v7m.other_sp = env->regs[13];
> -        env->regs[13] = tmp;
> -    }
> -}
> -
>  /* Switch M profile security state between NS and S */
>  void switch_v7m_security_state(CPUARMState *env, bool new_secstate)
>  {
> @@ -9247,6 +9227,26 @@ static bool do_v7m_function_return(ARMCPU *cpu)
>      return true;
>  }
>
> +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 pointer.
> +     */
> +    bool new_is_psp, old_is_psp = v7m_using_psp(env);
> +    uint32_t tmp;
> +
> +    env->v7m.exception = new_exc;
> +
> +    new_is_psp = v7m_using_psp(env);
> +
> +    if (old_is_psp != new_is_psp) {
> +        tmp = env->v7m.other_sp;
> +        env->v7m.other_sp = env->regs[13];
> +        env->regs[13] = tmp;
> +    }
> +}
> +
>  void arm_log_exception(int idx)
>  {
>      if (qemu_loglevel_mask(CPU_LOG_INT)) {


--
Alex Bennée


^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [Qemu-devel] [Qemu-arm] [PATCH v2 10/23] target/arm: Move the v7-M Security State helpers to v7m_helper
  2019-06-15 15:43 ` [Qemu-devel] [PATCH v2 10/23] target/arm: Move the v7-M Security State helpers to v7m_helper Philippe Mathieu-Daudé
@ 2019-06-17 14:08   ` Alex Bennée
  0 siblings, 0 replies; 51+ messages in thread
From: Alex Bennée @ 2019-06-17 14:08 UTC (permalink / raw)
  To: qemu-arm; +Cc: Peter Maydell, Philippe Mathieu-Daudé, qemu-devel


Philippe Mathieu-Daudé <philmd@redhat.com> writes:

> Signed-off-by: Philippe Mathieu-Daudé <philmd@redhat.com>

Reviewed-by: Alex Bennée <alex.bennee@linaro.org>

> ---
>  target/arm/helper.c     | 73 -----------------------------------------
>  target/arm/v7m_helper.c | 73 +++++++++++++++++++++++++++++++++++++++++
>  2 files changed, 73 insertions(+), 73 deletions(-)
>
> diff --git a/target/arm/helper.c b/target/arm/helper.c
> index b4fd9b42d7..cf76010ea1 100644
> --- a/target/arm/helper.c
> +++ b/target/arm/helper.c
> @@ -7885,79 +7885,6 @@ void HELPER(v7m_preserve_fp_state)(CPUARMState *env)
>       */
>  }
>
> -/*
> - * 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.
> - */
> -void write_v7m_control_spsel_for_secstate(CPUARMState *env,
> -                                          bool new_spsel,
> -                                          bool secstate)
> -{
> -    bool old_is_psp = v7m_using_psp(env);
> -
> -    env->v7m.control[secstate] =
> -        deposit32(env->v7m.control[secstate],
> -                  R_V7M_CONTROL_SPSEL_SHIFT,
> -                  R_V7M_CONTROL_SPSEL_LENGTH, new_spsel);
> -
> -    if (secstate == env->v7m.secure) {
> -        bool new_is_psp = v7m_using_psp(env);
> -        uint32_t tmp;
> -
> -        if (old_is_psp != new_is_psp) {
> -            tmp = env->v7m.other_sp;
> -            env->v7m.other_sp = env->regs[13];
> -            env->regs[13] = tmp;
> -        }
> -    }
> -}
> -
> -/*
> - * Write to v7M CONTROL.SPSEL bit. This may change the current
> - * stack pointer between Main and Process stack pointers.
> - */
> -void write_v7m_control_spsel(CPUARMState *env, bool new_spsel)
> -{
> -    write_v7m_control_spsel_for_secstate(env, new_spsel, env->v7m.secure);
> -}
> -
> -/* Switch M profile security state between NS and S */
> -void switch_v7m_security_state(CPUARMState *env, bool new_secstate)
> -{
> -    uint32_t new_ss_msp, new_ss_psp;
> -
> -    if (env->v7m.secure == 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 = env->v7m.other_ss_msp;
> -    new_ss_psp = env->v7m.other_ss_psp;
> -
> -    if (v7m_using_psp(env)) {
> -        env->v7m.other_ss_psp = env->regs[13];
> -        env->v7m.other_ss_msp = env->v7m.other_sp;
> -    } else {
> -        env->v7m.other_ss_msp = env->regs[13];
> -        env->v7m.other_ss_psp = env->v7m.other_sp;
> -    }
> -
> -    env->v7m.secure = new_secstate;
> -
> -    if (v7m_using_psp(env)) {
> -        env->regs[13] = new_ss_psp;
> -        env->v7m.other_sp = new_ss_msp;
> -    } else {
> -        env->regs[13] = new_ss_msp;
> -        env->v7m.other_sp = new_ss_psp;
> -    }
> -}
> -
>  static uint32_t *get_v7m_sp_ptr(CPUARMState *env, bool secure, bool threadmode,
>                                  bool spsel)
>  {
> diff --git a/target/arm/v7m_helper.c b/target/arm/v7m_helper.c
> index 321154966e..558e143039 100644
> --- a/target/arm/v7m_helper.c
> +++ b/target/arm/v7m_helper.c
> @@ -88,6 +88,79 @@ uint32_t HELPER(v7m_tt)(CPUARMState *env, uint32_t addr, uint32_t op)
>
>  #else
>
> +/*
> + * 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.
> + */
> +void write_v7m_control_spsel_for_secstate(CPUARMState *env,
> +                                          bool new_spsel,
> +                                          bool secstate)
> +{
> +    bool old_is_psp = v7m_using_psp(env);
> +
> +    env->v7m.control[secstate] =
> +        deposit32(env->v7m.control[secstate],
> +                  R_V7M_CONTROL_SPSEL_SHIFT,
> +                  R_V7M_CONTROL_SPSEL_LENGTH, new_spsel);
> +
> +    if (secstate == env->v7m.secure) {
> +        bool new_is_psp = v7m_using_psp(env);
> +        uint32_t tmp;
> +
> +        if (old_is_psp != new_is_psp) {
> +            tmp = env->v7m.other_sp;
> +            env->v7m.other_sp = env->regs[13];
> +            env->regs[13] = tmp;
> +        }
> +    }
> +}
> +
> +/*
> + * Write to v7M CONTROL.SPSEL bit. This may change the current
> + * stack pointer between Main and Process stack pointers.
> + */
> +void write_v7m_control_spsel(CPUARMState *env, bool new_spsel)
> +{
> +    write_v7m_control_spsel_for_secstate(env, new_spsel, env->v7m.secure);
> +}
> +
> +/* Switch M profile security state between NS and S */
> +void switch_v7m_security_state(CPUARMState *env, bool new_secstate)
> +{
> +    uint32_t new_ss_msp, new_ss_psp;
> +
> +    if (env->v7m.secure == 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 = env->v7m.other_ss_msp;
> +    new_ss_psp = env->v7m.other_ss_psp;
> +
> +    if (v7m_using_psp(env)) {
> +        env->v7m.other_ss_psp = env->regs[13];
> +        env->v7m.other_ss_msp = env->v7m.other_sp;
> +    } else {
> +        env->v7m.other_ss_msp = env->regs[13];
> +        env->v7m.other_ss_psp = env->v7m.other_sp;
> +    }
> +
> +    env->v7m.secure = new_secstate;
> +
> +    if (v7m_using_psp(env)) {
> +        env->regs[13] = new_ss_psp;
> +        env->v7m.other_sp = new_ss_msp;
> +    } else {
> +        env->regs[13] = new_ss_msp;
> +        env->v7m.other_sp = new_ss_psp;
> +    }
> +}
> +
>  void HELPER(v7m_bxns)(CPUARMState *env, uint32_t dest)
>  {
>      /*


--
Alex Bennée


^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [Qemu-devel] [Qemu-arm] [PATCH v2 11/23] target/arm: Declare v7m_cpacr_pass() publicly
  2019-06-15 15:43 ` [Qemu-devel] [PATCH v2 11/23] target/arm: Declare v7m_cpacr_pass() publicly Philippe Mathieu-Daudé
@ 2019-06-17 14:09   ` Alex Bennée
  0 siblings, 0 replies; 51+ messages in thread
From: Alex Bennée @ 2019-06-17 14:09 UTC (permalink / raw)
  To: qemu-arm; +Cc: Peter Maydell, Philippe Mathieu-Daudé, qemu-devel


Philippe Mathieu-Daudé <philmd@redhat.com> writes:

> In the next commit we will move exception handling routines to
> v7m_helper, so this function will be called from 2 different
> files. Declare it inlined in the "internals.h" header.
>
> Signed-off-by: Philippe Mathieu-Daudé <philmd@redhat.com>

Reviewed-by: Alex Bennée <alex.bennee@linaro.org>

> ---
>  target/arm/helper.c    | 19 -------------------
>  target/arm/internals.h | 21 +++++++++++++++++++++
>  2 files changed, 21 insertions(+), 19 deletions(-)
>
> diff --git a/target/arm/helper.c b/target/arm/helper.c
> index cf76010ea1..5d05db84d3 100644
> --- a/target/arm/helper.c
> +++ b/target/arm/helper.c
> @@ -7611,25 +7611,6 @@ uint32_t arm_phys_excp_target_el(CPUState *cs, uint32_t excp_idx,
>      return target_el;
>  }
>
> -/*
> - * Return true if the v7M CPACR permits access to the FPU for the specified
> - * security state and privilege level.
> - */
> -static bool v7m_cpacr_pass(CPUARMState *env, bool is_secure, bool is_priv)
> -{
> -    switch (extract32(env->v7m.cpacr[is_secure], 20, 2)) {
> -    case 0:
> -    case 2: /* UNPREDICTABLE: we treat like 0 */
> -        return false;
> -    case 1:
> -        return is_priv;
> -    case 3:
> -        return true;
> -    default:
> -        g_assert_not_reached();
> -    }
> -}
> -
>  /*
>   * What kind of stack write are we doing? This affects how exceptions
>   * generated during the stacking are treated.
> diff --git a/target/arm/internals.h b/target/arm/internals.h
> index 04711b317a..1d15af3f8b 100644
> --- a/target/arm/internals.h
> +++ b/target/arm/internals.h
> @@ -891,6 +891,27 @@ static inline uint32_t v7m_sp_limit(CPUARMState *env)
>      }
>  }
>
> +/**
> + * v7m_cpacr_pass:
> + * Return true if the v7M CPACR permits access to the FPU for the specified
> + * security state and privilege level.
> + */
> +static inline bool v7m_cpacr_pass(CPUARMState *env,
> +                                  bool is_secure, bool is_priv)
> +{
> +    switch (extract32(env->v7m.cpacr[is_secure], 20, 2)) {
> +    case 0:
> +    case 2: /* UNPREDICTABLE: we treat like 0 */
> +        return false;
> +    case 1:
> +        return is_priv;
> +    case 3:
> +        return true;
> +    default:
> +        g_assert_not_reached();
> +    }
> +}
> +
>  /**
>   * aarch32_mode_name(): Return name of the AArch32 CPU mode
>   * @psr: Program Status Register indicating CPU mode


--
Alex Bennée


^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [Qemu-devel] [Qemu-arm] [PATCH v2 12/23] target/arm: Move v7m exception handling routines to v7m_helper
  2019-06-15 15:43 ` [Qemu-devel] [PATCH v2 12/23] target/arm: Move v7m exception handling routines to v7m_helper Philippe Mathieu-Daudé
@ 2019-06-17 14:10   ` Alex Bennée
  0 siblings, 0 replies; 51+ messages in thread
From: Alex Bennée @ 2019-06-17 14:10 UTC (permalink / raw)
  To: qemu-arm
  Cc: Peter Maydell, Philippe Mathieu-Daudé, qemu-devel, Samuel Ortiz


Philippe Mathieu-Daudé <philmd@redhat.com> writes:

> From: Samuel Ortiz <sameo@linux.intel.com>
>
> In preparation for supporting TCG disablement on ARM, we move the v7m
> exception handling routines to v7m_helper.c
> arm_v7m_cpu_do_interrupt pulls a large number of static functions
> out of helper.c into m_helper.c because it is TCG dependent.
>
> Signed-off-by: Samuel Ortiz <sameo@linux.intel.com>
> [PMD: Patch rewritten]
> Signed-off-by: Philippe Mathieu-Daudé <philmd@redhat.com>

Reviewed-by: Alex Bennée <alex.bennee@linaro.org>

> ---
>  target/arm/helper.c     | 1876 ---------------------------------------
>  target/arm/v7m_helper.c | 1876 +++++++++++++++++++++++++++++++++++++++
>  2 files changed, 1876 insertions(+), 1876 deletions(-)
>
> diff --git a/target/arm/helper.c b/target/arm/helper.c
> index 5d05db84d3..24d88eef17 100644
> --- a/target/arm/helper.c
> +++ b/target/arm/helper.c
> @@ -7611,1530 +7611,6 @@ uint32_t arm_phys_excp_target_el(CPUState *cs, uint32_t excp_idx,
>      return target_el;
>  }
>
> -/*
> - * 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 = CPU(cpu);
> -    CPUARMState *env = &cpu->env;
> -    MemTxAttrs attrs = {};
> -    MemTxResult txres;
> -    target_ulong page_size;
> -    hwaddr physaddr;
> -    int prot;
> -    ARMMMUFaultInfo fi = {};
> -    bool secure = 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 == ARMFault_QEMU_SFault) {
> -            if (mode == STACK_LAZYFP) {
> -                qemu_log_mask(CPU_LOG_INT,
> -                              "...SecureFault with SFSR.LSPERR "
> -                              "during lazy stacking\n");
> -                env->v7m.sfsr |= R_V7M_SFSR_LSPERR_MASK;
> -            } else {
> -                qemu_log_mask(CPU_LOG_INT,
> -                              "...SecureFault with SFSR.AUVIOL "
> -                              "during stacking\n");
> -                env->v7m.sfsr |= R_V7M_SFSR_AUVIOL_MASK;
> -            }
> -            env->v7m.sfsr |= R_V7M_SFSR_SFARVALID_MASK;
> -            env->v7m.sfar = addr;
> -            exc = ARMV7M_EXCP_SECURE;
> -            exc_secure = false;
> -        } else {
> -            if (mode == STACK_LAZYFP) {
> -                qemu_log_mask(CPU_LOG_INT,
> -                              "...MemManageFault with CFSR.MLSPERR\n");
> -                env->v7m.cfsr[secure] |= R_V7M_CFSR_MLSPERR_MASK;
> -            } else {
> -                qemu_log_mask(CPU_LOG_INT,
> -                              "...MemManageFault with CFSR.MSTKERR\n");
> -                env->v7m.cfsr[secure] |= R_V7M_CFSR_MSTKERR_MASK;
> -            }
> -            exc = ARMV7M_EXCP_MEM;
> -            exc_secure = secure;
> -        }
> -        goto pend_fault;
> -    }
> -    address_space_stl_le(arm_addressspace(cs, attrs), physaddr, value,
> -                         attrs, &txres);
> -    if (txres != MEMTX_OK) {
> -        /* BusFault trying to write the data */
> -        if (mode == STACK_LAZYFP) {
> -            qemu_log_mask(CPU_LOG_INT, "...BusFault with BFSR.LSPERR\n");
> -            env->v7m.cfsr[M_REG_NS] |= R_V7M_CFSR_LSPERR_MASK;
> -        } else {
> -            qemu_log_mask(CPU_LOG_INT, "...BusFault with BFSR.STKERR\n");
> -            env->v7m.cfsr[M_REG_NS] |= R_V7M_CFSR_STKERR_MASK;
> -        }
> -        exc = ARMV7M_EXCP_BUS;
> -        exc_secure = 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 = CPU(cpu);
> -    CPUARMState *env = &cpu->env;
> -    MemTxAttrs attrs = {};
> -    MemTxResult txres;
> -    target_ulong page_size;
> -    hwaddr physaddr;
> -    int prot;
> -    ARMMMUFaultInfo fi = {};
> -    bool secure = 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 == ARMFault_QEMU_SFault) {
> -            qemu_log_mask(CPU_LOG_INT,
> -                          "...SecureFault with SFSR.AUVIOL during unstack\n");
> -            env->v7m.sfsr |= R_V7M_SFSR_AUVIOL_MASK | R_V7M_SFSR_SFARVALID_MASK;
> -            env->v7m.sfar = addr;
> -            exc = ARMV7M_EXCP_SECURE;
> -            exc_secure = false;
> -        } else {
> -            qemu_log_mask(CPU_LOG_INT,
> -                          "...MemManageFault with CFSR.MUNSTKERR\n");
> -            env->v7m.cfsr[secure] |= R_V7M_CFSR_MUNSTKERR_MASK;
> -            exc = ARMV7M_EXCP_MEM;
> -            exc_secure = secure;
> -        }
> -        goto pend_fault;
> -    }
> -
> -    value = address_space_ldl(arm_addressspace(cs, attrs), physaddr,
> -                              attrs, &txres);
> -    if (txres != 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] |= R_V7M_CFSR_UNSTKERR_MASK;
> -        exc = ARMV7M_EXCP_BUS;
> -        exc_secure = false;
> -        goto pend_fault;
> -    }
> -
> -    *dest = 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 = env_archcpu(env);
> -    bool is_secure = env->v7m.fpccr[M_REG_S] & R_V7M_FPCCR_S_MASK;
> -    bool negpri = !(env->v7m.fpccr[M_REG_S] & R_V7M_FPCCR_HFRDY_MASK);
> -    bool is_priv = !(env->v7m.fpccr[is_secure] & R_V7M_FPCCR_USER_MASK);
> -    bool splimviol = env->v7m.fpccr[is_secure] & R_V7M_FPCCR_SPLIMVIOL_MASK;
> -    uint32_t fpcar = env->v7m.fpcar[is_secure];
> -    bool stacked_ok = true;
> -    bool ts = is_secure && (env->v7m.fpccr[M_REG_S] & R_V7M_FPCCR_TS_MASK);
> -    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_secure);
> -        env->v7m.cfsr[is_secure] |= R_V7M_CFSR_NOCP_MASK;
> -        stacked_ok = 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] |= R_V7M_CFSR_NOCP_MASK;
> -        stacked_ok = false;
> -    }
> -
> -    if (!splimviol && stacked_ok) {
> -        /* We only stack if the stack limit wasn't violated */
> -        int i;
> -        ARMMMUIdx mmu_idx;
> -
> -        mmu_idx = arm_v7m_mmu_idx_all(env, is_secure, is_priv, negpri);
> -        for (i = 0; i < (ts ? 32 : 16); i += 2) {
> -            uint64_t dn = *aa32_vfp_dreg(env, i / 2);
> -            uint32_t faddr = fpcar + 4 * i;
> -            uint32_t slo = extract64(dn, 0, 32);
> -            uint32_t shi = extract64(dn, 32, 32);
> -
> -            if (i >= 16) {
> -                faddr += 8; /* skip the slot for the FPSCR */
> -            }
> -            stacked_ok = 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 = 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 = !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] &= ~R_V7M_FPCCR_LSPACT_MASK;
> -
> -    if (ts) {
> -        /* Clear s0 to s31 and the FPSCR */
> -        int i;
> -
> -        for (i = 0; i < 32; i += 2) {
> -            *aa32_vfp_dreg(env, i / 2) = 0;
> -        }
> -        vfp_set_fpscr(env, 0);
> -    }
> -    /*
> -     * Otherwise s0 to s15 and FPSCR are UNKNOWN; we choose to leave them
> -     * unchanged.
> -     */
> -}
> -
> -static uint32_t *get_v7m_sp_ptr(CPUARMState *env, bool secure, bool threadmode,
> -                                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 = threadmode && spsel;
> -
> -    if (secure == env->v7m.secure) {
> -        if (want_psp == 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 = CPU(cpu);
> -    CPUARMState *env = &cpu->env;
> -    MemTxResult result;
> -    uint32_t addr = env->v7m.vecbase[targets_secure] + exc * 4;
> -    uint32_t vector_entry;
> -    MemTxAttrs attrs = {};
> -    ARMMMUIdx mmu_idx;
> -    bool exc_secure;
> -
> -    mmu_idx = 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 = targets_secure;
> -    attrs.user = false;
> -
> -    if (arm_feature(env, ARM_FEATURE_M_SECURITY)) {
> -        V8M_SAttributes sattrs = {};
> -
> -        v8m_security_lookup(env, addr, MMU_DATA_LOAD, mmu_idx, &sattrs);
> -        if (sattrs.ns) {
> -            attrs.secure = false;
> -        } else if (!targets_secure) {
> -            /* NS access to S memory */
> -            goto load_fail;
> -        }
> -    }
> -
> -    vector_entry = address_space_ldl(arm_addressspace(cs, attrs), addr,
> -                                     attrs, &result);
> -    if (result != MEMTX_OK) {
> -        goto load_fail;
> -    }
> -    *pvec = 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_derived()).
> -     */
> -    exc_secure = targets_secure ||
> -        !(cpu->env.v7m.aircr & R_V7M_AIRCR_BFHFNMINS_MASK);
> -    env->v7m.hfsr |= R_V7M_HFSR_VECTTBL_MASK | R_V7M_HFSR_FORCED_MASK;
> -    armv7m_nvic_set_pending_derived(env->nvic, ARMV7M_EXCP_HARD, exc_secure);
> -    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 = 0xfefa125a;
> -
> -    if (!arm_feature(env, ARM_FEATURE_VFP) || (lr & R_V7M_EXCRET_FTYPE_MASK)) {
> -        sig |= 1;
> -    }
> -    return sig;
> -}
> -
> -static bool v7m_push_callee_stack(ARMCPU *cpu, uint32_t lr, bool dotailchain,
> -                                  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 = &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 = ignore_faults ? STACK_IGNFAULTS : STACK_NORMAL;
> -
> -    if (dotailchain) {
> -        bool mode = lr & R_V7M_EXCRET_MODE_MASK;
> -        bool priv = !(env->v7m.control[M_REG_S] & R_V7M_CONTROL_NPRIV_MASK) ||
> -            !mode;
> -
> -        mmu_idx = arm_v7m_mmu_idx_for_secstate_and_priv(env, M_REG_S, priv);
> -        frame_sp_p = get_v7m_sp_ptr(env, M_REG_S, mode,
> -                                    lr & R_V7M_EXCRET_SPSEL_MASK);
> -        want_psp = mode && (lr & R_V7M_EXCRET_SPSEL_MASK);
> -        if (want_psp) {
> -            limit = env->v7m.psplim[M_REG_S];
> -        } else {
> -            limit = env->v7m.msplim[M_REG_S];
> -        }
> -    } else {
> -        mmu_idx = arm_mmu_idx(env);
> -        frame_sp_p = &env->regs[13];
> -        limit = v7m_sp_limit(env);
> -    }
> -
> -    frameptr = *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] |= R_V7M_CFSR_STKOF_MASK;
> -        armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_USAGE,
> -                                env->v7m.secure);
> -        *frame_sp_p = 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 = v7m_integrity_sig(env, lr);
> -    stacked_ok =
> -        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, smode) &&
> -        v7m_stack_write(cpu, frameptr + 0x24, env->regs[11], mmu_idx, smode);
> -
> -    /* Update SP regardless of whether any of the stack accesses failed. */
> -    *frame_sp_p = 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 = &cpu->env;
> -    uint32_t addr;
> -    bool targets_secure;
> -    int exc;
> -    bool push_failed = 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 |= R_V7M_EXCRET_FTYPE_MASK;
> -        }
> -        lr = 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 &= ~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 = v7m_push_callee_stack(cpu, lr, dotailchain,
> -                                                        ignore_stackfaults);
> -                }
> -                lr |= R_V7M_EXCRET_DCRS_MASK;
> -            }
> -        }
> -
> -        lr &= ~R_V7M_EXCRET_ES_MASK;
> -        if (targets_secure || !arm_feature(env, ARM_FEATURE_M_SECURITY)) {
> -            lr |= R_V7M_EXCRET_ES_MASK;
> -        }
> -        lr &= ~R_V7M_EXCRET_SPSEL_MASK;
> -        if (env->v7m.control[targets_secure] & R_V7M_CONTROL_SPSEL_MASK) {
> -            lr |= 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 = 0; i < 13; i++) {
> -                    /* r4..r11 are callee-saves, zero only if EXCRET.S == 1 */
> -                    if (i < 4 || i > 11 || (lr & R_V7M_EXCRET_S_MASK)) {
> -                        env->regs[i] = 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 stacking");
> -        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 load");
> -        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 SPSEL */
> -    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] &=
> -        ~(R_V7M_CONTROL_FPCA_MASK | R_V7M_CONTROL_SFPA_MASK);
> -    /* Clear IT bits */
> -    env->condexec_bits = 0;
> -    env->regs[14] = lr;
> -    env->regs[15] = addr & 0xfffffffe;
> -    env->thumb = 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 = env->v7m.secure;
> -    void *nvic = 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 = &env->v7m.fpccr[M_REG_S];
> -    uint32_t *fpccr_ns = &env->v7m.fpccr[M_REG_NS];
> -    uint32_t *fpccr = &env->v7m.fpccr[is_secure];
> -    bool hfrdy, bfrdy, mmrdy, ns_ufrdy, s_ufrdy, sfrdy, monrdy;
> -
> -    env->v7m.fpcar[is_secure] = frameptr & ~0x7;
> -
> -    if (apply_splim && arm_feature(env, ARM_FEATURE_V8)) {
> -        bool splimviol;
> -        uint32_t splim = v7m_sp_limit(env);
> -        bool ign = armv7m_nvic_neg_prio_requested(nvic, is_secure) &&
> -            (env->v7m.ccr[is_secure] & R_V7M_CCR_STKOFHFNMIGN_MASK);
> -
> -        splimviol = !ign && frameptr < splim;
> -        *fpccr = FIELD_DP32(*fpccr, V7M_FPCCR, SPLIMVIOL, splimviol);
> -    }
> -
> -    *fpccr = FIELD_DP32(*fpccr, V7M_FPCCR, LSPACT, 1);
> -
> -    *fpccr_s = FIELD_DP32(*fpccr_s, V7M_FPCCR, S, is_secure);
> -
> -    *fpccr = FIELD_DP32(*fpccr, V7M_FPCCR, USER, arm_current_el(env) == 0);
> -
> -    *fpccr = FIELD_DP32(*fpccr, V7M_FPCCR, THREAD,
> -                        !arm_v7m_is_handler_mode(env));
> -
> -    hfrdy = armv7m_nvic_get_ready_status(nvic, ARMV7M_EXCP_HARD, false);
> -    *fpccr_s = FIELD_DP32(*fpccr_s, V7M_FPCCR, HFRDY, hfrdy);
> -
> -    bfrdy = armv7m_nvic_get_ready_status(nvic, ARMV7M_EXCP_BUS, false);
> -    *fpccr_s = FIELD_DP32(*fpccr_s, V7M_FPCCR, BFRDY, bfrdy);
> -
> -    mmrdy = armv7m_nvic_get_ready_status(nvic, ARMV7M_EXCP_MEM, is_secure);
> -    *fpccr = FIELD_DP32(*fpccr, V7M_FPCCR, MMRDY, mmrdy);
> -
> -    ns_ufrdy = armv7m_nvic_get_ready_status(nvic, ARMV7M_EXCP_USAGE, false);
> -    *fpccr_ns = FIELD_DP32(*fpccr_ns, V7M_FPCCR, UFRDY, ns_ufrdy);
> -
> -    monrdy = armv7m_nvic_get_ready_status(nvic, ARMV7M_EXCP_DEBUG, false);
> -    *fpccr_s = FIELD_DP32(*fpccr_s, V7M_FPCCR, MONRDY, monrdy);
> -
> -    if (arm_feature(env, ARM_FEATURE_M_SECURITY)) {
> -        s_ufrdy = armv7m_nvic_get_ready_status(nvic, ARMV7M_EXCP_USAGE, true);
> -        *fpccr_s = FIELD_DP32(*fpccr_s, V7M_FPCCR, UFRDY, s_ufrdy);
> -
> -        sfrdy = armv7m_nvic_get_ready_status(nvic, ARMV7M_EXCP_SECURE, false);
> -        *fpccr_s = 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 = env->v7m.fpccr[M_REG_S] & R_V7M_FPCCR_S_MASK;
> -    bool lspact = 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) != 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_STACK
> -     * 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 = env->v7m.fpccr[M_REG_S] & R_V7M_FPCCR_TS_MASK;
> -        int i;
> -
> -        for (i = 0; i < (ts ? 32 : 16); i += 2) {
> -            uint64_t dn = *aa32_vfp_dreg(env, i / 2);
> -            uint32_t faddr = fptr + 4 * i;
> -            uint32_t slo = extract64(dn, 0, 32);
> -            uint32_t shi = extract64(dn, 32, 32);
> -
> -            if (i >= 16) {
> -                faddr += 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_state.
> -         */
> -        if (ts) {
> -            for (i = 0; i < 32; i += 2) {
> -                *aa32_vfp_dreg(env, i / 2) = 0;
> -            }
> -            vfp_set_fpscr(env, 0);
> -        }
> -    } else {
> -        v7m_update_fpccr(env, fptr, false);
> -    }
> -
> -    env->v7m.control[M_REG_S] &= ~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) != 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] &= ~R_V7M_FPCCR_LSPACT_MASK;
> -    } else {
> -        bool ts = 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 = 0; i < (ts ? 32 : 16); i += 2) {
> -            uint32_t slo, shi;
> -            uint64_t dn;
> -            uint32_t faddr = fptr + 4 * i;
> -
> -            if (i >= 16) {
> -                faddr += 8; /* skip the slot for the FPSCR */
> -            }
> -
> -            slo = cpu_ldl_data(env, faddr);
> -            shi = cpu_ldl_data(env, faddr + 4);
> -
> -            dn = (uint64_t) shi << 32 | slo;
> -            *aa32_vfp_dreg(env, i / 2) = dn;
> -        }
> -        fpscr = cpu_ldl_data(env, fptr + 0x40);
> -        vfp_set_fpscr(env, fpscr);
> -    }
> -
> -    env->v7m.control[M_REG_S] |= 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 = true, limitviol = false;
> -    CPUARMState *env = &cpu->env;
> -    uint32_t xpsr = xpsr_read(env);
> -    uint32_t frameptr = env->regs[13];
> -    ARMMMUIdx mmu_idx = arm_mmu_idx(env);
> -    uint32_t framesize;
> -    bool nsacr_cp10 = 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 = 0xa8;
> -        } else {
> -            framesize = 0x68;
> -        }
> -    } else {
> -        framesize = 0x20;
> -    }
> -
> -    /* Align stack pointer if the guest wants that */
> -    if ((frameptr & 4) &&
> -        (env->v7m.ccr[env->v7m.secure] & R_V7M_CCR_STKALIGN_MASK)) {
> -        frameptr -= 4;
> -        xpsr |= XPSR_SPREALIGN;
> -    }
> -
> -    xpsr &= ~XPSR_SFPA;
> -    if (env->v7m.secure &&
> -        (env->v7m.control[M_REG_S] & R_V7M_CONTROL_SFPA_MASK)) {
> -        xpsr |= XPSR_SFPA;
> -    }
> -
> -    frameptr -= framesize;
> -
> -    if (arm_feature(env, ARM_FEATURE_V8)) {
> -        uint32_t limit = 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] |= R_V7M_CFSR_STKOF_MASK;
> -            armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_USAGE,
> -                                    env->v7m.secure);
> -            env->regs[13] = 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 = true;
> -            stacked_ok = 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 = 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 = env->v7m.fpccr[M_REG_S] & R_V7M_FPCCR_S_MASK;
> -        bool lspact = 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 |= 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] |= 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 = v7m_cpacr_pass(env, env->v7m.secure,
> -                                                 arm_current_el(env) != 0);
> -
> -                if (stacked_ok && !cpacr_pass) {
> -                    /*
> -                     * Take UsageFault if CPACR forbids access. The pseudocode
> -                     * here does a full CheckCPEnabled() but we know the NSACR
> -                     * check can never fail as we have already handled that.
> -                     */
> -                    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] |= R_V7M_CFSR_NOCP_MASK;
> -                    stacked_ok = false;
> -                }
> -
> -                for (i = 0; i < ((framesize == 0xa8) ? 32 : 16); i += 2) {
> -                    uint64_t dn = *aa32_vfp_dreg(env, i / 2);
> -                    uint32_t faddr = frameptr + 0x20 + 4 * i;
> -                    uint32_t slo = extract64(dn, 0, 32);
> -                    uint32_t shi = extract64(dn, 32, 32);
> -
> -                    if (i >= 16) {
> -                        faddr += 8; /* skip the slot for the FPSCR */
> -                    }
> -                    stacked_ok = 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 = stacked_ok &&
> -                    v7m_stack_write(cpu, frameptr + 0x60,
> -                                    vfp_get_fpscr(env), mmu_idx, STACK_NORMAL);
> -                if (cpacr_pass) {
> -                    for (i = 0; i < ((framesize == 0xa8) ? 32 : 16); i += 2) {
> -                        *aa32_vfp_dreg(env, i / 2) = 0;
> -                    }
> -                    vfp_set_fpscr(env, 0);
> -                }
> -            } else {
> -                /* Lazy stacking enabled, save necessary info to stack later */
> -                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] = frameptr;
> -    }
> -
> -    return !stacked_ok;
> -}
> -
> -static void do_v7m_exception_exit(ARMCPU *cpu)
> -{
> -    CPUARMState *env = &cpu->env;
> -    uint32_t excret;
> -    uint32_t xpsr, xpsr_mask;
> -    bool ufault = false;
> -    bool sfault = false;
> -    bool return_to_sp_process;
> -    bool return_to_handler;
> -    bool rettobase = false;
> -    bool exc_secure = 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 = env->regs[15];
> -    if (env->thumb) {
> -        excret |= 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) != R_V7M_EXCRET_RES1_MASK) {
> -        qemu_log_mask(LOG_GUEST_ERROR, "M profile: zero high bits in exception "
> -                      "exit PC value 0x%" PRIx32 " are UNPREDICTABLE\n",
> -                      excret);
> -    }
> -
> -    ftype = 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 = 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 = 1;
> -            /* For all other purposes, treat ES as 0 (R_HXSR) */
> -            excret &= ~R_V7M_EXCRET_ES_MASK;
> -        }
> -        exc_secure = excret & R_V7M_EXCRET_ES_MASK;
> -    }
> -
> -    if (env->v7m.exception != 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 >= 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) >= 0) {
> -                env->v7m.faultmask[exc_secure] = 0;
> -            }
> -        } else {
> -            env->v7m.faultmask[M_REG_NS] = 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 = 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 != 1"
> -         * where we have 'rettobase == false'.)
> -         */
> -        rettobase = true;
> -        break;
> -    default:
> -        g_assert_not_reached();
> -    }
> -
> -    return_to_handler = !(excret & R_V7M_EXCRET_MODE_MASK);
> -    return_to_sp_process = excret & R_V7M_EXCRET_SPSEL_MASK;
> -    return_to_secure = 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 == 1 or DCRS == 0 or ES == 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 = true;
> -            }
> -        }
> -        if (excret & R_V7M_EXCRET_RES0_MASK) {
> -            ufault = 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 = true;
> -            }
> -            break;
> -        default:
> -            ufault = 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_secure);
> -
> -    /*
> -     * 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 |= 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 deactivation\n");
> -            v7m_exception_taken(cpu, excret, true, false);
> -            return;
> -        } else {
> -            /* Clear s0..s15 and FPSCR */
> -            int i;
> -
> -            for (i = 0; i < 16; i += 2) {
> -                *aa32_vfp_dreg(env, i / 2) = 0;
> -            }
> -            vfp_set_fpscr(env, 0);
> -        }
> -    }
> -
> -    if (sfault) {
> -        env->v7m.sfsr |= 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] |= R_V7M_CFSR_INVPC_MASK;
> -        armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_USAGE, env->v7m.secure);
> -        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 = get_v7m_sp_ptr(env,
> -                                              return_to_secure,
> -                                              !return_to_handler,
> -                                              return_to_sp_process);
> -        uint32_t frameptr = *frame_sp_p;
> -        bool pop_ok = true;
> -        ARMMMUIdx mmu_idx;
> -        bool return_to_priv = return_to_handler ||
> -            !(env->v7m.control[return_to_secure] & R_V7M_CONTROL_NPRIV_MASK);
> -
> -        mmu_idx = arm_v7m_mmu_idx_for_secstate_and_priv(env, return_to_secure,
> -                                                        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 SP "
> -                          "for destination state is UNPREDICTABLE\n");
> -        }
> -
> -        /* Do we need to pop callee-saved registers? */
> -        if (return_to_secure &&
> -            ((excret & R_V7M_EXCRET_ES_MASK) == 0 ||
> -             (excret & R_V7M_EXCRET_DCRS_MASK) == 0)) {
> -            uint32_t actual_sig;
> -
> -            pop_ok = v7m_stack_read(cpu, &actual_sig, frameptr, mmu_idx);
> -
> -            if (pop_ok && v7m_integrity_sig(env, excret) != actual_sig) {
> -                /* Take a SecureFault on the current stack */
> -                env->v7m.sfsr |= R_V7M_SFSR_INVIS_MASK;
> -                armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_SECURE, false);
> -                qemu_log_mask(CPU_LOG_INT, "...taking SecureFault on existing "
> -                              "stackframe: failed exception return integrity "
> -                              "signature check\n");
> -                v7m_exception_taken(cpu, excret, true, false);
> -                return;
> -            }
> -
> -            pop_ok = 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_idx) &&
> -                v7m_stack_read(cpu, &env->regs[7], frameptr + 0x14, mmu_idx) &&
> -                v7m_stack_read(cpu, &env->regs[8], frameptr + 0x18, mmu_idx) &&
> -                v7m_stack_read(cpu, &env->regs[9], frameptr + 0x1c, mmu_idx) &&
> -                v7m_stack_read(cpu, &env->regs[10], frameptr + 0x20, mmu_idx) &&
> -                v7m_stack_read(cpu, &env->regs[11], frameptr + 0x24, mmu_idx);
> -
> -            frameptr += 0x28;
> -        }
> -
> -        /* Pop registers */
> -        pop_ok = 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 specified
> -         * to be UNPREDICTABLE. In practice actual v7M hardware seems to ignore
> -         * the lsbit, and there are several RTOSes out there which incorrectly
> -         * 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, but
> -         * complain about the badly behaved guest.
> -         */
> -        if (env->regs[15] & 1) {
> -            env->regs[15] &= ~1U;
> -            if (!arm_feature(env, ARM_FEATURE_V8)) {
> -                qemu_log_mask(LOG_GUEST_ERROR,
> -                              "M profile return from interrupt with misaligned "
> -                              "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 = (xpsr & XPSR_EXCP) != 0;
> -            if (return_to_handler != will_be_handler) {
> -                /*
> -                 * Take an INVPC UsageFault on the current stack.
> -                 * By this point we will have switched to the security state
> -                 * 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] |= R_V7M_CFSR_INVPC_MASK;
> -                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;
> -            }
> -        }
> -
> -        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, false);
> -                env->v7m.sfsr |= R_V7M_SFSR_LSERR_MASK;
> -                qemu_log_mask(CPU_LOG_INT,
> -                              "...taking SecureFault on existing stackframe: "
> -                              "Secure LSPACT set but exception return is "
> -                              "not to secure state\n");
> -                v7m_exception_taken(cpu, excret, true, false);
> -                return;
> -            }
> -
> -            restore_s16_s31 = 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] &= ~R_V7M_FPCCR_LSPACT_MASK;
> -            } else {
> -                int i;
> -                uint32_t fpscr;
> -                bool cpacr_pass, nsacr_pass;
> -
> -                cpacr_pass = v7m_cpacr_pass(env, return_to_secure,
> -                                            return_to_priv);
> -                nsacr_pass = 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] |= R_V7M_CFSR_NOCP_MASK;
> -                    qemu_log_mask(CPU_LOG_INT,
> -                                  "...taking UsageFault on existing "
> -                                  "stackframe: CPACR.CP10 prevents unstacking "
> -                                  "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] |= R_V7M_CFSR_INVPC_MASK;
> -                    qemu_log_mask(CPU_LOG_INT,
> -                                  "...taking Secure UsageFault on existing "
> -                                  "stackframe: NSACR.CP10 prevents unstacking "
> -                                  "FP regs\n");
> -                    v7m_exception_taken(cpu, excret, true, false);
> -                    return;
> -                }
> -
> -                for (i = 0; i < (restore_s16_s31 ? 32 : 16); i += 2) {
> -                    uint32_t slo, shi;
> -                    uint64_t dn;
> -                    uint32_t faddr = frameptr + 0x20 + 4 * i;
> -
> -                    if (i >= 16) {
> -                        faddr += 8; /* Skip the slot for the FPSCR */
> -                    }
> -
> -                    pop_ok = pop_ok &&
> -                        v7m_stack_read(cpu, &slo, faddr, mmu_idx) &&
> -                        v7m_stack_read(cpu, &shi, faddr + 4, mmu_idx);
> -
> -                    if (!pop_ok) {
> -                        break;
> -                    }
> -
> -                    dn = (uint64_t)shi << 32 | slo;
> -                    *aa32_vfp_dreg(env, i / 2) = dn;
> -                }
> -                pop_ok = 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 = 0; i < (restore_s16_s31 ? 32 : 16); i += 2) {
> -                        *aa32_vfp_dreg(env, i / 2) = 0;
> -                    }
> -                    vfp_set_fpscr(env, 0);
> -                }
> -            }
> -        }
> -        env->v7m.control[M_REG_S] = FIELD_DP32(env->v7m.control[M_REG_S],
> -                                               V7M_CONTROL, FPCA, !ftype);
> -
> -        /* Commit to consuming the stack frame */
> -        frameptr += 0x20;
> -        if (!ftype) {
> -            frameptr += 0x48;
> -            if (restore_s16_s31) {
> -                frameptr += 0x40;
> -            }
> -        }
> -        /*
> -         * Undo stack alignment (the SPREALIGN bit indicates that the original
> -         * 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. (Adding 4
> -         * would work too but a logical OR is how the pseudocode specifies it.)
> -         */
> -        if (xpsr & XPSR_SPREALIGN) {
> -            frameptr |= 4;
> -        }
> -        *frame_sp_p = frameptr;
> -    }
> -
> -    xpsr_mask = ~(XPSR_SPREALIGN | XPSR_SFPA);
> -    if (!arm_feature(env, ARM_FEATURE_THUMB_DSP)) {
> -        xpsr_mask &= ~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 = xpsr & XPSR_SFPA;
> -
> -        env->v7m.control[M_REG_S] = 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 != 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] |= R_V7M_CFSR_INVPC_MASK;
> -        ignore_stackfaults = 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 = &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 = !arm_v7m_is_handler_mode(env);
> -        spsel = env->v7m.control[M_REG_S] & R_V7M_CONTROL_SPSEL_MASK;
> -
> -        frame_sp_p = get_v7m_sp_ptr(env, true, threadmode, spsel);
> -        frameptr = *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 = arm_v7m_mmu_idx_for_secstate(env, true);
> -        oi = make_memop_idx(MO_LE, arm_to_core_mmu_idx(mmu_idx));
> -        newpc = helper_le_ldul_mmu(env, frameptr, oi, 0);
> -        newpsr = helper_le_ldul_mmu(env, frameptr + 4, oi, 0);
> -
> -        /* Consistency checks on new IPSR */
> -        newpsr_exc = newpsr & XPSR_EXCP;
> -        if (!((env->v7m.exception == 0 && newpsr_exc == 0) ||
> -              (env->v7m.exception == 1 && newpsr_exc != 0))) {
> -            /* Pend the fault and tell our caller to take it */
> -            env->v7m.cfsr[env->v7m.secure] |= 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 = frameptr + 8;
> -    }
> -
> -    /* This invalidates frame_sp_p */
> -    switch_v7m_security_state(env, true);
> -    env->v7m.exception = newpsr_exc;
> -    env->v7m.control[M_REG_S] &= ~R_V7M_CONTROL_SFPA_MASK;
> -    if (newpsr & XPSR_SFPA) {
> -        env->v7m.control[M_REG_S] |= R_V7M_CONTROL_SFPA_MASK;
> -    }
> -    xpsr_write(env, 0, XPSR_IT);
> -    env->thumb = newpc & 1;
> -    env->regs[15] = newpc & ~1;
> -
> -    qemu_log_mask(CPU_LOG_INT, "...function return successful\n");
> -    return true;
> -}
> -
>  void write_v7m_exception(CPUARMState *env, uint32_t new_exc)
>  {
>      /*
> @@ -9193,358 +7669,6 @@ void arm_log_exception(int idx)
>      }
>  }
>
> -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 success,
> -     * or false on failure (in which case we will have pended the appropriate
> -     * 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 = CPU(cpu);
> -    CPUARMState *env = &cpu->env;
> -    V8M_SAttributes sattrs = {};
> -    MemTxAttrs attrs = {};
> -    ARMMMUFaultInfo fi = {};
> -    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 |= 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] |= R_V7M_CFSR_IACCVIOL_MASK;
> -        armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_MEM, env->v7m.secure);
> -        qemu_log_mask(CPU_LOG_INT, "...really MemManage with CFSR.IACCVIOL\n");
> -        return false;
> -    }
> -    *insn = address_space_lduw_le(arm_addressspace(cs, attrs), physaddr,
> -                                 attrs, &txres);
> -    if (txres != MEMTX_OK) {
> -        env->v7m.cfsr[M_REG_NS] |= 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 = &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 = 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 != 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 != 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" PRIx32
> -                  ", executing it\n", env->regs[15]);
> -    env->regs[14] &= ~1;
> -    env->v7m.control[M_REG_S] &= ~R_V7M_CONTROL_SFPA_MASK;
> -    switch_v7m_security_state(env, true);
> -    xpsr_write(env, 0, XPSR_IT);
> -    env->regs[15] += 4;
> -    return true;
> -
> -gen_invep:
> -    env->v7m.sfsr |= 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 = ARM_CPU(cs);
> -    CPUARMState *env = &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.secure);
> -        env->v7m.cfsr[env->v7m.secure] |= 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 == 3) {
> -            target_secstate = M_REG_S;
> -        } else {
> -            target_secstate = env->v7m.secure;
> -        }
> -        armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_USAGE, target_secstate);
> -        env->v7m.cfsr[target_secstate] |= R_V7M_CFSR_NOCP_MASK;
> -        break;
> -    }
> -    case EXCP_INVSTATE:
> -        armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_USAGE, env->v7m.secure);
> -        env->v7m.cfsr[env->v7m.secure] |= R_V7M_CFSR_INVSTATE_MASK;
> -        break;
> -    case EXCP_STKOF:
> -        armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_USAGE, env->v7m.secure);
> -        env->v7m.cfsr[env->v7m.secure] |= R_V7M_CFSR_STKOF_MASK;
> -        break;
> -    case EXCP_LSERR:
> -        armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_SECURE, false);
> -        env->v7m.sfsr |= R_V7M_SFSR_LSERR_MASK;
> -        break;
> -    case EXCP_UNALIGNED:
> -        armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_USAGE, env->v7m.secure);
> -        env->v7m.cfsr[env->v7m.secure] |= 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.secure);
> -        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 address
> -             * 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 |= R_V7M_SFSR_INVTRAN_MASK;
> -                    qemu_log_mask(CPU_LOG_INT,
> -                                  "...really SecureFault with SFSR.INVTRAN\n");
> -                } else {
> -                    env->v7m.sfsr |= 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 |= 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] |= 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] |=
> -                    (R_V7M_CFSR_PRECISERR_MASK | R_V7M_CFSR_BFARVALID_MASK);
> -                env->v7m.bfar = 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] |= R_V7M_CFSR_IACCVIOL_MASK;
> -                qemu_log_mask(CPU_LOG_INT, "...with CFSR.IACCVIOL\n");
> -                break;
> -            case EXCP_DATA_ABORT:
> -                env->v7m.cfsr[env->v7m.secure] |=
> -                    (R_V7M_CFSR_DACCVIOL_MASK | R_V7M_CFSR_MMARVALID_MASK);
> -                env->v7m.mmfar[env->v7m.secure] = env->exception.vaddress;
> -                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 = arm_lduw_code(env, env->regs[15], arm_sctlr_b(env)) & 0xff;
> -            if (nr == 0xab) {
> -                env->regs[15] += 2;
> -                qemu_log_mask(CPU_LOG_INT,
> -                              "...handling as semihosting call 0x%x\n",
> -                              env->regs[0]);
> -                env->regs[0] = 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] >= 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 = 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 |= R_V7M_EXCRET_S_MASK;
> -        }
> -        if (!(env->v7m.control[M_REG_S] & R_V7M_CONTROL_FPCA_MASK)) {
> -            lr |= R_V7M_EXCRET_FTYPE_MASK;
> -        }
> -    } else {
> -        lr = 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 |= R_V7M_EXCRET_SPSEL_MASK;
> -        }
> -    }
> -    if (!arm_v7m_is_handler_mode(env)) {
> -        lr |= R_V7M_EXCRET_MODE_MASK;
> -    }
> -
> -    ignore_stackfaults = 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 AArch64
>   * execution state.
> diff --git a/target/arm/v7m_helper.c b/target/arm/v7m_helper.c
> index 558e143039..b50bb98e06 100644
> --- a/target/arm/v7m_helper.c
> +++ b/target/arm/v7m_helper.c
> @@ -724,4 +724,1880 @@ uint32_t HELPER(v7m_tt)(CPUARMState *env, uint32_t addr, uint32_t op)
>      return tt_resp;
>  }
>
> +/*
> + * 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 = CPU(cpu);
> +    CPUARMState *env = &cpu->env;
> +    MemTxAttrs attrs = {};
> +    MemTxResult txres;
> +    target_ulong page_size;
> +    hwaddr physaddr;
> +    int prot;
> +    ARMMMUFaultInfo fi = {};
> +    bool secure = 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 == ARMFault_QEMU_SFault) {
> +            if (mode == STACK_LAZYFP) {
> +                qemu_log_mask(CPU_LOG_INT,
> +                              "...SecureFault with SFSR.LSPERR "
> +                              "during lazy stacking\n");
> +                env->v7m.sfsr |= R_V7M_SFSR_LSPERR_MASK;
> +            } else {
> +                qemu_log_mask(CPU_LOG_INT,
> +                              "...SecureFault with SFSR.AUVIOL "
> +                              "during stacking\n");
> +                env->v7m.sfsr |= R_V7M_SFSR_AUVIOL_MASK;
> +            }
> +            env->v7m.sfsr |= R_V7M_SFSR_SFARVALID_MASK;
> +            env->v7m.sfar = addr;
> +            exc = ARMV7M_EXCP_SECURE;
> +            exc_secure = false;
> +        } else {
> +            if (mode == STACK_LAZYFP) {
> +                qemu_log_mask(CPU_LOG_INT,
> +                              "...MemManageFault with CFSR.MLSPERR\n");
> +                env->v7m.cfsr[secure] |= R_V7M_CFSR_MLSPERR_MASK;
> +            } else {
> +                qemu_log_mask(CPU_LOG_INT,
> +                              "...MemManageFault with CFSR.MSTKERR\n");
> +                env->v7m.cfsr[secure] |= R_V7M_CFSR_MSTKERR_MASK;
> +            }
> +            exc = ARMV7M_EXCP_MEM;
> +            exc_secure = secure;
> +        }
> +        goto pend_fault;
> +    }
> +    address_space_stl_le(arm_addressspace(cs, attrs), physaddr, value,
> +                         attrs, &txres);
> +    if (txres != MEMTX_OK) {
> +        /* BusFault trying to write the data */
> +        if (mode == STACK_LAZYFP) {
> +            qemu_log_mask(CPU_LOG_INT, "...BusFault with BFSR.LSPERR\n");
> +            env->v7m.cfsr[M_REG_NS] |= R_V7M_CFSR_LSPERR_MASK;
> +        } else {
> +            qemu_log_mask(CPU_LOG_INT, "...BusFault with BFSR.STKERR\n");
> +            env->v7m.cfsr[M_REG_NS] |= R_V7M_CFSR_STKERR_MASK;
> +        }
> +        exc = ARMV7M_EXCP_BUS;
> +        exc_secure = 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 = CPU(cpu);
> +    CPUARMState *env = &cpu->env;
> +    MemTxAttrs attrs = {};
> +    MemTxResult txres;
> +    target_ulong page_size;
> +    hwaddr physaddr;
> +    int prot;
> +    ARMMMUFaultInfo fi = {};
> +    bool secure = 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 == ARMFault_QEMU_SFault) {
> +            qemu_log_mask(CPU_LOG_INT,
> +                          "...SecureFault with SFSR.AUVIOL during unstack\n");
> +            env->v7m.sfsr |= R_V7M_SFSR_AUVIOL_MASK | R_V7M_SFSR_SFARVALID_MASK;
> +            env->v7m.sfar = addr;
> +            exc = ARMV7M_EXCP_SECURE;
> +            exc_secure = false;
> +        } else {
> +            qemu_log_mask(CPU_LOG_INT,
> +                          "...MemManageFault with CFSR.MUNSTKERR\n");
> +            env->v7m.cfsr[secure] |= R_V7M_CFSR_MUNSTKERR_MASK;
> +            exc = ARMV7M_EXCP_MEM;
> +            exc_secure = secure;
> +        }
> +        goto pend_fault;
> +    }
> +
> +    value = address_space_ldl(arm_addressspace(cs, attrs), physaddr,
> +                              attrs, &txres);
> +    if (txres != 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] |= R_V7M_CFSR_UNSTKERR_MASK;
> +        exc = ARMV7M_EXCP_BUS;
> +        exc_secure = false;
> +        goto pend_fault;
> +    }
> +
> +    *dest = 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 = env_archcpu(env);
> +    bool is_secure = env->v7m.fpccr[M_REG_S] & R_V7M_FPCCR_S_MASK;
> +    bool negpri = !(env->v7m.fpccr[M_REG_S] & R_V7M_FPCCR_HFRDY_MASK);
> +    bool is_priv = !(env->v7m.fpccr[is_secure] & R_V7M_FPCCR_USER_MASK);
> +    bool splimviol = env->v7m.fpccr[is_secure] & R_V7M_FPCCR_SPLIMVIOL_MASK;
> +    uint32_t fpcar = env->v7m.fpcar[is_secure];
> +    bool stacked_ok = true;
> +    bool ts = is_secure && (env->v7m.fpccr[M_REG_S] & R_V7M_FPCCR_TS_MASK);
> +    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_secure);
> +        env->v7m.cfsr[is_secure] |= R_V7M_CFSR_NOCP_MASK;
> +        stacked_ok = 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] |= R_V7M_CFSR_NOCP_MASK;
> +        stacked_ok = false;
> +    }
> +
> +    if (!splimviol && stacked_ok) {
> +        /* We only stack if the stack limit wasn't violated */
> +        int i;
> +        ARMMMUIdx mmu_idx;
> +
> +        mmu_idx = arm_v7m_mmu_idx_all(env, is_secure, is_priv, negpri);
> +        for (i = 0; i < (ts ? 32 : 16); i += 2) {
> +            uint64_t dn = *aa32_vfp_dreg(env, i / 2);
> +            uint32_t faddr = fpcar + 4 * i;
> +            uint32_t slo = extract64(dn, 0, 32);
> +            uint32_t shi = extract64(dn, 32, 32);
> +
> +            if (i >= 16) {
> +                faddr += 8; /* skip the slot for the FPSCR */
> +            }
> +            stacked_ok = 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 = 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 = !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] &= ~R_V7M_FPCCR_LSPACT_MASK;
> +
> +    if (ts) {
> +        /* Clear s0 to s31 and the FPSCR */
> +        int i;
> +
> +        for (i = 0; i < 32; i += 2) {
> +            *aa32_vfp_dreg(env, i / 2) = 0;
> +        }
> +        vfp_set_fpscr(env, 0);
> +    }
> +    /*
> +     * Otherwise s0 to s15 and FPSCR are UNKNOWN; we choose to leave them
> +     * unchanged.
> +     */
> +}
> +
> +static uint32_t *get_v7m_sp_ptr(CPUARMState *env, bool secure, bool threadmode,
> +                                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 = threadmode && spsel;
> +
> +    if (secure == env->v7m.secure) {
> +        if (want_psp == 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 = CPU(cpu);
> +    CPUARMState *env = &cpu->env;
> +    MemTxResult result;
> +    uint32_t addr = env->v7m.vecbase[targets_secure] + exc * 4;
> +    uint32_t vector_entry;
> +    MemTxAttrs attrs = {};
> +    ARMMMUIdx mmu_idx;
> +    bool exc_secure;
> +
> +    mmu_idx = 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 = targets_secure;
> +    attrs.user = false;
> +
> +    if (arm_feature(env, ARM_FEATURE_M_SECURITY)) {
> +        V8M_SAttributes sattrs = {};
> +
> +        v8m_security_lookup(env, addr, MMU_DATA_LOAD, mmu_idx, &sattrs);
> +        if (sattrs.ns) {
> +            attrs.secure = false;
> +        } else if (!targets_secure) {
> +            /* NS access to S memory */
> +            goto load_fail;
> +        }
> +    }
> +
> +    vector_entry = address_space_ldl(arm_addressspace(cs, attrs), addr,
> +                                     attrs, &result);
> +    if (result != MEMTX_OK) {
> +        goto load_fail;
> +    }
> +    *pvec = 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_derived()).
> +     */
> +    exc_secure = targets_secure ||
> +        !(cpu->env.v7m.aircr & R_V7M_AIRCR_BFHFNMINS_MASK);
> +    env->v7m.hfsr |= R_V7M_HFSR_VECTTBL_MASK | R_V7M_HFSR_FORCED_MASK;
> +    armv7m_nvic_set_pending_derived(env->nvic, ARMV7M_EXCP_HARD, exc_secure);
> +    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 = 0xfefa125a;
> +
> +    if (!arm_feature(env, ARM_FEATURE_VFP) || (lr & R_V7M_EXCRET_FTYPE_MASK)) {
> +        sig |= 1;
> +    }
> +    return sig;
> +}
> +
> +static bool v7m_push_callee_stack(ARMCPU *cpu, uint32_t lr, bool dotailchain,
> +                                  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 = &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 = ignore_faults ? STACK_IGNFAULTS : STACK_NORMAL;
> +
> +    if (dotailchain) {
> +        bool mode = lr & R_V7M_EXCRET_MODE_MASK;
> +        bool priv = !(env->v7m.control[M_REG_S] & R_V7M_CONTROL_NPRIV_MASK) ||
> +            !mode;
> +
> +        mmu_idx = arm_v7m_mmu_idx_for_secstate_and_priv(env, M_REG_S, priv);
> +        frame_sp_p = get_v7m_sp_ptr(env, M_REG_S, mode,
> +                                    lr & R_V7M_EXCRET_SPSEL_MASK);
> +        want_psp = mode && (lr & R_V7M_EXCRET_SPSEL_MASK);
> +        if (want_psp) {
> +            limit = env->v7m.psplim[M_REG_S];
> +        } else {
> +            limit = env->v7m.msplim[M_REG_S];
> +        }
> +    } else {
> +        mmu_idx = arm_mmu_idx(env);
> +        frame_sp_p = &env->regs[13];
> +        limit = v7m_sp_limit(env);
> +    }
> +
> +    frameptr = *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] |= R_V7M_CFSR_STKOF_MASK;
> +        armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_USAGE,
> +                                env->v7m.secure);
> +        *frame_sp_p = 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 = v7m_integrity_sig(env, lr);
> +    stacked_ok =
> +        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, smode) &&
> +        v7m_stack_write(cpu, frameptr + 0x24, env->regs[11], mmu_idx, smode);
> +
> +    /* Update SP regardless of whether any of the stack accesses failed. */
> +    *frame_sp_p = 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 = &cpu->env;
> +    uint32_t addr;
> +    bool targets_secure;
> +    int exc;
> +    bool push_failed = 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 |= R_V7M_EXCRET_FTYPE_MASK;
> +        }
> +        lr = 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 &= ~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 = v7m_push_callee_stack(cpu, lr, dotailchain,
> +                                                        ignore_stackfaults);
> +                }
> +                lr |= R_V7M_EXCRET_DCRS_MASK;
> +            }
> +        }
> +
> +        lr &= ~R_V7M_EXCRET_ES_MASK;
> +        if (targets_secure || !arm_feature(env, ARM_FEATURE_M_SECURITY)) {
> +            lr |= R_V7M_EXCRET_ES_MASK;
> +        }
> +        lr &= ~R_V7M_EXCRET_SPSEL_MASK;
> +        if (env->v7m.control[targets_secure] & R_V7M_CONTROL_SPSEL_MASK) {
> +            lr |= 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 = 0; i < 13; i++) {
> +                    /* r4..r11 are callee-saves, zero only if EXCRET.S == 1 */
> +                    if (i < 4 || i > 11 || (lr & R_V7M_EXCRET_S_MASK)) {
> +                        env->regs[i] = 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 stacking");
> +        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 load");
> +        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 SPSEL */
> +    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] &=
> +        ~(R_V7M_CONTROL_FPCA_MASK | R_V7M_CONTROL_SFPA_MASK);
> +    /* Clear IT bits */
> +    env->condexec_bits = 0;
> +    env->regs[14] = lr;
> +    env->regs[15] = addr & 0xfffffffe;
> +    env->thumb = 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 = env->v7m.secure;
> +    void *nvic = 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 = &env->v7m.fpccr[M_REG_S];
> +    uint32_t *fpccr_ns = &env->v7m.fpccr[M_REG_NS];
> +    uint32_t *fpccr = &env->v7m.fpccr[is_secure];
> +    bool hfrdy, bfrdy, mmrdy, ns_ufrdy, s_ufrdy, sfrdy, monrdy;
> +
> +    env->v7m.fpcar[is_secure] = frameptr & ~0x7;
> +
> +    if (apply_splim && arm_feature(env, ARM_FEATURE_V8)) {
> +        bool splimviol;
> +        uint32_t splim = v7m_sp_limit(env);
> +        bool ign = armv7m_nvic_neg_prio_requested(nvic, is_secure) &&
> +            (env->v7m.ccr[is_secure] & R_V7M_CCR_STKOFHFNMIGN_MASK);
> +
> +        splimviol = !ign && frameptr < splim;
> +        *fpccr = FIELD_DP32(*fpccr, V7M_FPCCR, SPLIMVIOL, splimviol);
> +    }
> +
> +    *fpccr = FIELD_DP32(*fpccr, V7M_FPCCR, LSPACT, 1);
> +
> +    *fpccr_s = FIELD_DP32(*fpccr_s, V7M_FPCCR, S, is_secure);
> +
> +    *fpccr = FIELD_DP32(*fpccr, V7M_FPCCR, USER, arm_current_el(env) == 0);
> +
> +    *fpccr = FIELD_DP32(*fpccr, V7M_FPCCR, THREAD,
> +                        !arm_v7m_is_handler_mode(env));
> +
> +    hfrdy = armv7m_nvic_get_ready_status(nvic, ARMV7M_EXCP_HARD, false);
> +    *fpccr_s = FIELD_DP32(*fpccr_s, V7M_FPCCR, HFRDY, hfrdy);
> +
> +    bfrdy = armv7m_nvic_get_ready_status(nvic, ARMV7M_EXCP_BUS, false);
> +    *fpccr_s = FIELD_DP32(*fpccr_s, V7M_FPCCR, BFRDY, bfrdy);
> +
> +    mmrdy = armv7m_nvic_get_ready_status(nvic, ARMV7M_EXCP_MEM, is_secure);
> +    *fpccr = FIELD_DP32(*fpccr, V7M_FPCCR, MMRDY, mmrdy);
> +
> +    ns_ufrdy = armv7m_nvic_get_ready_status(nvic, ARMV7M_EXCP_USAGE, false);
> +    *fpccr_ns = FIELD_DP32(*fpccr_ns, V7M_FPCCR, UFRDY, ns_ufrdy);
> +
> +    monrdy = armv7m_nvic_get_ready_status(nvic, ARMV7M_EXCP_DEBUG, false);
> +    *fpccr_s = FIELD_DP32(*fpccr_s, V7M_FPCCR, MONRDY, monrdy);
> +
> +    if (arm_feature(env, ARM_FEATURE_M_SECURITY)) {
> +        s_ufrdy = armv7m_nvic_get_ready_status(nvic, ARMV7M_EXCP_USAGE, true);
> +        *fpccr_s = FIELD_DP32(*fpccr_s, V7M_FPCCR, UFRDY, s_ufrdy);
> +
> +        sfrdy = armv7m_nvic_get_ready_status(nvic, ARMV7M_EXCP_SECURE, false);
> +        *fpccr_s = 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 = env->v7m.fpccr[M_REG_S] & R_V7M_FPCCR_S_MASK;
> +    bool lspact = 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) != 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_STACK
> +     * 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 = env->v7m.fpccr[M_REG_S] & R_V7M_FPCCR_TS_MASK;
> +        int i;
> +
> +        for (i = 0; i < (ts ? 32 : 16); i += 2) {
> +            uint64_t dn = *aa32_vfp_dreg(env, i / 2);
> +            uint32_t faddr = fptr + 4 * i;
> +            uint32_t slo = extract64(dn, 0, 32);
> +            uint32_t shi = extract64(dn, 32, 32);
> +
> +            if (i >= 16) {
> +                faddr += 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_state.
> +         */
> +        if (ts) {
> +            for (i = 0; i < 32; i += 2) {
> +                *aa32_vfp_dreg(env, i / 2) = 0;
> +            }
> +            vfp_set_fpscr(env, 0);
> +        }
> +    } else {
> +        v7m_update_fpccr(env, fptr, false);
> +    }
> +
> +    env->v7m.control[M_REG_S] &= ~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) != 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] &= ~R_V7M_FPCCR_LSPACT_MASK;
> +    } else {
> +        bool ts = 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 = 0; i < (ts ? 32 : 16); i += 2) {
> +            uint32_t slo, shi;
> +            uint64_t dn;
> +            uint32_t faddr = fptr + 4 * i;
> +
> +            if (i >= 16) {
> +                faddr += 8; /* skip the slot for the FPSCR */
> +            }
> +
> +            slo = cpu_ldl_data(env, faddr);
> +            shi = cpu_ldl_data(env, faddr + 4);
> +
> +            dn = (uint64_t) shi << 32 | slo;
> +            *aa32_vfp_dreg(env, i / 2) = dn;
> +        }
> +        fpscr = cpu_ldl_data(env, fptr + 0x40);
> +        vfp_set_fpscr(env, fpscr);
> +    }
> +
> +    env->v7m.control[M_REG_S] |= 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 = true, limitviol = false;
> +    CPUARMState *env = &cpu->env;
> +    uint32_t xpsr = xpsr_read(env);
> +    uint32_t frameptr = env->regs[13];
> +    ARMMMUIdx mmu_idx = arm_mmu_idx(env);
> +    uint32_t framesize;
> +    bool nsacr_cp10 = 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 = 0xa8;
> +        } else {
> +            framesize = 0x68;
> +        }
> +    } else {
> +        framesize = 0x20;
> +    }
> +
> +    /* Align stack pointer if the guest wants that */
> +    if ((frameptr & 4) &&
> +        (env->v7m.ccr[env->v7m.secure] & R_V7M_CCR_STKALIGN_MASK)) {
> +        frameptr -= 4;
> +        xpsr |= XPSR_SPREALIGN;
> +    }
> +
> +    xpsr &= ~XPSR_SFPA;
> +    if (env->v7m.secure &&
> +        (env->v7m.control[M_REG_S] & R_V7M_CONTROL_SFPA_MASK)) {
> +        xpsr |= XPSR_SFPA;
> +    }
> +
> +    frameptr -= framesize;
> +
> +    if (arm_feature(env, ARM_FEATURE_V8)) {
> +        uint32_t limit = 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] |= R_V7M_CFSR_STKOF_MASK;
> +            armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_USAGE,
> +                                    env->v7m.secure);
> +            env->regs[13] = 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 = true;
> +            stacked_ok = 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 = 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 = env->v7m.fpccr[M_REG_S] & R_V7M_FPCCR_S_MASK;
> +        bool lspact = 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 |= 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] |= 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 = v7m_cpacr_pass(env, env->v7m.secure,
> +                                                 arm_current_el(env) != 0);
> +
> +                if (stacked_ok && !cpacr_pass) {
> +                    /*
> +                     * Take UsageFault if CPACR forbids access. The pseudocode
> +                     * here does a full CheckCPEnabled() but we know the NSACR
> +                     * check can never fail as we have already handled that.
> +                     */
> +                    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] |= R_V7M_CFSR_NOCP_MASK;
> +                    stacked_ok = false;
> +                }
> +
> +                for (i = 0; i < ((framesize == 0xa8) ? 32 : 16); i += 2) {
> +                    uint64_t dn = *aa32_vfp_dreg(env, i / 2);
> +                    uint32_t faddr = frameptr + 0x20 + 4 * i;
> +                    uint32_t slo = extract64(dn, 0, 32);
> +                    uint32_t shi = extract64(dn, 32, 32);
> +
> +                    if (i >= 16) {
> +                        faddr += 8; /* skip the slot for the FPSCR */
> +                    }
> +                    stacked_ok = 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 = stacked_ok &&
> +                    v7m_stack_write(cpu, frameptr + 0x60,
> +                                    vfp_get_fpscr(env), mmu_idx, STACK_NORMAL);
> +                if (cpacr_pass) {
> +                    for (i = 0; i < ((framesize == 0xa8) ? 32 : 16); i += 2) {
> +                        *aa32_vfp_dreg(env, i / 2) = 0;
> +                    }
> +                    vfp_set_fpscr(env, 0);
> +                }
> +            } else {
> +                /* Lazy stacking enabled, save necessary info to stack later */
> +                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] = frameptr;
> +    }
> +
> +    return !stacked_ok;
> +}
> +
> +static void do_v7m_exception_exit(ARMCPU *cpu)
> +{
> +    CPUARMState *env = &cpu->env;
> +    uint32_t excret;
> +    uint32_t xpsr, xpsr_mask;
> +    bool ufault = false;
> +    bool sfault = false;
> +    bool return_to_sp_process;
> +    bool return_to_handler;
> +    bool rettobase = false;
> +    bool exc_secure = 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 = env->regs[15];
> +    if (env->thumb) {
> +        excret |= 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) != R_V7M_EXCRET_RES1_MASK) {
> +        qemu_log_mask(LOG_GUEST_ERROR, "M profile: zero high bits in exception "
> +                      "exit PC value 0x%" PRIx32 " are UNPREDICTABLE\n",
> +                      excret);
> +    }
> +
> +    ftype = 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 = 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 = 1;
> +            /* For all other purposes, treat ES as 0 (R_HXSR) */
> +            excret &= ~R_V7M_EXCRET_ES_MASK;
> +        }
> +        exc_secure = excret & R_V7M_EXCRET_ES_MASK;
> +    }
> +
> +    if (env->v7m.exception != 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 >= 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) >= 0) {
> +                env->v7m.faultmask[exc_secure] = 0;
> +            }
> +        } else {
> +            env->v7m.faultmask[M_REG_NS] = 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 = 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 != 1"
> +         * where we have 'rettobase == false'.)
> +         */
> +        rettobase = true;
> +        break;
> +    default:
> +        g_assert_not_reached();
> +    }
> +
> +    return_to_handler = !(excret & R_V7M_EXCRET_MODE_MASK);
> +    return_to_sp_process = excret & R_V7M_EXCRET_SPSEL_MASK;
> +    return_to_secure = 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 == 1 or DCRS == 0 or ES == 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 = true;
> +            }
> +        }
> +        if (excret & R_V7M_EXCRET_RES0_MASK) {
> +            ufault = 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 = true;
> +            }
> +            break;
> +        default:
> +            ufault = 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_secure);
> +
> +    /*
> +     * 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 |= 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 deactivation\n");
> +            v7m_exception_taken(cpu, excret, true, false);
> +            return;
> +        } else {
> +            /* Clear s0..s15 and FPSCR */
> +            int i;
> +
> +            for (i = 0; i < 16; i += 2) {
> +                *aa32_vfp_dreg(env, i / 2) = 0;
> +            }
> +            vfp_set_fpscr(env, 0);
> +        }
> +    }
> +
> +    if (sfault) {
> +        env->v7m.sfsr |= 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] |= R_V7M_CFSR_INVPC_MASK;
> +        armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_USAGE, env->v7m.secure);
> +        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 = get_v7m_sp_ptr(env,
> +                                              return_to_secure,
> +                                              !return_to_handler,
> +                                              return_to_sp_process);
> +        uint32_t frameptr = *frame_sp_p;
> +        bool pop_ok = true;
> +        ARMMMUIdx mmu_idx;
> +        bool return_to_priv = return_to_handler ||
> +            !(env->v7m.control[return_to_secure] & R_V7M_CONTROL_NPRIV_MASK);
> +
> +        mmu_idx = arm_v7m_mmu_idx_for_secstate_and_priv(env, return_to_secure,
> +                                                        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 SP "
> +                          "for destination state is UNPREDICTABLE\n");
> +        }
> +
> +        /* Do we need to pop callee-saved registers? */
> +        if (return_to_secure &&
> +            ((excret & R_V7M_EXCRET_ES_MASK) == 0 ||
> +             (excret & R_V7M_EXCRET_DCRS_MASK) == 0)) {
> +            uint32_t actual_sig;
> +
> +            pop_ok = v7m_stack_read(cpu, &actual_sig, frameptr, mmu_idx);
> +
> +            if (pop_ok && v7m_integrity_sig(env, excret) != actual_sig) {
> +                /* Take a SecureFault on the current stack */
> +                env->v7m.sfsr |= R_V7M_SFSR_INVIS_MASK;
> +                armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_SECURE, false);
> +                qemu_log_mask(CPU_LOG_INT, "...taking SecureFault on existing "
> +                              "stackframe: failed exception return integrity "
> +                              "signature check\n");
> +                v7m_exception_taken(cpu, excret, true, false);
> +                return;
> +            }
> +
> +            pop_ok = 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_idx) &&
> +                v7m_stack_read(cpu, &env->regs[7], frameptr + 0x14, mmu_idx) &&
> +                v7m_stack_read(cpu, &env->regs[8], frameptr + 0x18, mmu_idx) &&
> +                v7m_stack_read(cpu, &env->regs[9], frameptr + 0x1c, mmu_idx) &&
> +                v7m_stack_read(cpu, &env->regs[10], frameptr + 0x20, mmu_idx) &&
> +                v7m_stack_read(cpu, &env->regs[11], frameptr + 0x24, mmu_idx);
> +
> +            frameptr += 0x28;
> +        }
> +
> +        /* Pop registers */
> +        pop_ok = 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 specified
> +         * to be UNPREDICTABLE. In practice actual v7M hardware seems to ignore
> +         * the lsbit, and there are several RTOSes out there which incorrectly
> +         * 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, but
> +         * complain about the badly behaved guest.
> +         */
> +        if (env->regs[15] & 1) {
> +            env->regs[15] &= ~1U;
> +            if (!arm_feature(env, ARM_FEATURE_V8)) {
> +                qemu_log_mask(LOG_GUEST_ERROR,
> +                              "M profile return from interrupt with misaligned "
> +                              "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 = (xpsr & XPSR_EXCP) != 0;
> +            if (return_to_handler != will_be_handler) {
> +                /*
> +                 * Take an INVPC UsageFault on the current stack.
> +                 * By this point we will have switched to the security state
> +                 * 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] |= R_V7M_CFSR_INVPC_MASK;
> +                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;
> +            }
> +        }
> +
> +        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, false);
> +                env->v7m.sfsr |= R_V7M_SFSR_LSERR_MASK;
> +                qemu_log_mask(CPU_LOG_INT,
> +                              "...taking SecureFault on existing stackframe: "
> +                              "Secure LSPACT set but exception return is "
> +                              "not to secure state\n");
> +                v7m_exception_taken(cpu, excret, true, false);
> +                return;
> +            }
> +
> +            restore_s16_s31 = 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] &= ~R_V7M_FPCCR_LSPACT_MASK;
> +            } else {
> +                int i;
> +                uint32_t fpscr;
> +                bool cpacr_pass, nsacr_pass;
> +
> +                cpacr_pass = v7m_cpacr_pass(env, return_to_secure,
> +                                            return_to_priv);
> +                nsacr_pass = 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] |= R_V7M_CFSR_NOCP_MASK;
> +                    qemu_log_mask(CPU_LOG_INT,
> +                                  "...taking UsageFault on existing "
> +                                  "stackframe: CPACR.CP10 prevents unstacking "
> +                                  "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] |= R_V7M_CFSR_INVPC_MASK;
> +                    qemu_log_mask(CPU_LOG_INT,
> +                                  "...taking Secure UsageFault on existing "
> +                                  "stackframe: NSACR.CP10 prevents unstacking "
> +                                  "FP regs\n");
> +                    v7m_exception_taken(cpu, excret, true, false);
> +                    return;
> +                }
> +
> +                for (i = 0; i < (restore_s16_s31 ? 32 : 16); i += 2) {
> +                    uint32_t slo, shi;
> +                    uint64_t dn;
> +                    uint32_t faddr = frameptr + 0x20 + 4 * i;
> +
> +                    if (i >= 16) {
> +                        faddr += 8; /* Skip the slot for the FPSCR */
> +                    }
> +
> +                    pop_ok = pop_ok &&
> +                        v7m_stack_read(cpu, &slo, faddr, mmu_idx) &&
> +                        v7m_stack_read(cpu, &shi, faddr + 4, mmu_idx);
> +
> +                    if (!pop_ok) {
> +                        break;
> +                    }
> +
> +                    dn = (uint64_t)shi << 32 | slo;
> +                    *aa32_vfp_dreg(env, i / 2) = dn;
> +                }
> +                pop_ok = 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 = 0; i < (restore_s16_s31 ? 32 : 16); i += 2) {
> +                        *aa32_vfp_dreg(env, i / 2) = 0;
> +                    }
> +                    vfp_set_fpscr(env, 0);
> +                }
> +            }
> +        }
> +        env->v7m.control[M_REG_S] = FIELD_DP32(env->v7m.control[M_REG_S],
> +                                               V7M_CONTROL, FPCA, !ftype);
> +
> +        /* Commit to consuming the stack frame */
> +        frameptr += 0x20;
> +        if (!ftype) {
> +            frameptr += 0x48;
> +            if (restore_s16_s31) {
> +                frameptr += 0x40;
> +            }
> +        }
> +        /*
> +         * Undo stack alignment (the SPREALIGN bit indicates that the original
> +         * 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. (Adding 4
> +         * would work too but a logical OR is how the pseudocode specifies it.)
> +         */
> +        if (xpsr & XPSR_SPREALIGN) {
> +            frameptr |= 4;
> +        }
> +        *frame_sp_p = frameptr;
> +    }
> +
> +    xpsr_mask = ~(XPSR_SPREALIGN | XPSR_SFPA);
> +    if (!arm_feature(env, ARM_FEATURE_THUMB_DSP)) {
> +        xpsr_mask &= ~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 = xpsr & XPSR_SFPA;
> +
> +        env->v7m.control[M_REG_S] = 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 != 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] |= R_V7M_CFSR_INVPC_MASK;
> +        ignore_stackfaults = 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 = &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 = !arm_v7m_is_handler_mode(env);
> +        spsel = env->v7m.control[M_REG_S] & R_V7M_CONTROL_SPSEL_MASK;
> +
> +        frame_sp_p = get_v7m_sp_ptr(env, true, threadmode, spsel);
> +        frameptr = *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 = arm_v7m_mmu_idx_for_secstate(env, true);
> +        oi = make_memop_idx(MO_LE, arm_to_core_mmu_idx(mmu_idx));
> +        newpc = helper_le_ldul_mmu(env, frameptr, oi, 0);
> +        newpsr = helper_le_ldul_mmu(env, frameptr + 4, oi, 0);
> +
> +        /* Consistency checks on new IPSR */
> +        newpsr_exc = newpsr & XPSR_EXCP;
> +        if (!((env->v7m.exception == 0 && newpsr_exc == 0) ||
> +              (env->v7m.exception == 1 && newpsr_exc != 0))) {
> +            /* Pend the fault and tell our caller to take it */
> +            env->v7m.cfsr[env->v7m.secure] |= 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 = frameptr + 8;
> +    }
> +
> +    /* This invalidates frame_sp_p */
> +    switch_v7m_security_state(env, true);
> +    env->v7m.exception = newpsr_exc;
> +    env->v7m.control[M_REG_S] &= ~R_V7M_CONTROL_SFPA_MASK;
> +    if (newpsr & XPSR_SFPA) {
> +        env->v7m.control[M_REG_S] |= R_V7M_CONTROL_SFPA_MASK;
> +    }
> +    xpsr_write(env, 0, XPSR_IT);
> +    env->thumb = newpc & 1;
> +    env->regs[15] = 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 success,
> +     * or false on failure (in which case we will have pended the appropriate
> +     * 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 = CPU(cpu);
> +    CPUARMState *env = &cpu->env;
> +    V8M_SAttributes sattrs = {};
> +    MemTxAttrs attrs = {};
> +    ARMMMUFaultInfo fi = {};
> +    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 |= 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] |= R_V7M_CFSR_IACCVIOL_MASK;
> +        armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_MEM, env->v7m.secure);
> +        qemu_log_mask(CPU_LOG_INT, "...really MemManage with CFSR.IACCVIOL\n");
> +        return false;
> +    }
> +    *insn = address_space_lduw_le(arm_addressspace(cs, attrs), physaddr,
> +                                 attrs, &txres);
> +    if (txres != MEMTX_OK) {
> +        env->v7m.cfsr[M_REG_NS] |= 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 = &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 = 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 != 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 != 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" PRIx32
> +                  ", executing it\n", env->regs[15]);
> +    env->regs[14] &= ~1;
> +    env->v7m.control[M_REG_S] &= ~R_V7M_CONTROL_SFPA_MASK;
> +    switch_v7m_security_state(env, true);
> +    xpsr_write(env, 0, XPSR_IT);
> +    env->regs[15] += 4;
> +    return true;
> +
> +gen_invep:
> +    env->v7m.sfsr |= 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 = ARM_CPU(cs);
> +    CPUARMState *env = &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.secure);
> +        env->v7m.cfsr[env->v7m.secure] |= 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 == 3) {
> +            target_secstate = M_REG_S;
> +        } else {
> +            target_secstate = env->v7m.secure;
> +        }
> +        armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_USAGE, target_secstate);
> +        env->v7m.cfsr[target_secstate] |= R_V7M_CFSR_NOCP_MASK;
> +        break;
> +    }
> +    case EXCP_INVSTATE:
> +        armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_USAGE, env->v7m.secure);
> +        env->v7m.cfsr[env->v7m.secure] |= R_V7M_CFSR_INVSTATE_MASK;
> +        break;
> +    case EXCP_STKOF:
> +        armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_USAGE, env->v7m.secure);
> +        env->v7m.cfsr[env->v7m.secure] |= R_V7M_CFSR_STKOF_MASK;
> +        break;
> +    case EXCP_LSERR:
> +        armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_SECURE, false);
> +        env->v7m.sfsr |= R_V7M_SFSR_LSERR_MASK;
> +        break;
> +    case EXCP_UNALIGNED:
> +        armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_USAGE, env->v7m.secure);
> +        env->v7m.cfsr[env->v7m.secure] |= 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.secure);
> +        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 address
> +             * 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 |= R_V7M_SFSR_INVTRAN_MASK;
> +                    qemu_log_mask(CPU_LOG_INT,
> +                                  "...really SecureFault with SFSR.INVTRAN\n");
> +                } else {
> +                    env->v7m.sfsr |= 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 |= 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] |= 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] |=
> +                    (R_V7M_CFSR_PRECISERR_MASK | R_V7M_CFSR_BFARVALID_MASK);
> +                env->v7m.bfar = 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] |= R_V7M_CFSR_IACCVIOL_MASK;
> +                qemu_log_mask(CPU_LOG_INT, "...with CFSR.IACCVIOL\n");
> +                break;
> +            case EXCP_DATA_ABORT:
> +                env->v7m.cfsr[env->v7m.secure] |=
> +                    (R_V7M_CFSR_DACCVIOL_MASK | R_V7M_CFSR_MMARVALID_MASK);
> +                env->v7m.mmfar[env->v7m.secure] = env->exception.vaddress;
> +                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 = arm_lduw_code(env, env->regs[15], arm_sctlr_b(env)) & 0xff;
> +            if (nr == 0xab) {
> +                env->regs[15] += 2;
> +                qemu_log_mask(CPU_LOG_INT,
> +                              "...handling as semihosting call 0x%x\n",
> +                              env->regs[0]);
> +                env->regs[0] = 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] >= 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 = 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 |= R_V7M_EXCRET_S_MASK;
> +        }
> +        if (!(env->v7m.control[M_REG_S] & R_V7M_CONTROL_FPCA_MASK)) {
> +            lr |= R_V7M_EXCRET_FTYPE_MASK;
> +        }
> +    } else {
> +        lr = 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 |= R_V7M_EXCRET_SPSEL_MASK;
> +        }
> +    }
> +    if (!arm_v7m_is_handler_mode(env)) {
> +        lr |= R_V7M_EXCRET_MODE_MASK;
> +    }
> +
> +    ignore_stackfaults = v7m_push_stack(cpu);
> +    v7m_exception_taken(cpu, lr, false, ignore_stackfaults);
> +}
> +
>  #endif /* CONFIG_USER_ONLY */


--
Alex Bennée


^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [Qemu-devel] [Qemu-arm] [PATCH v2 13/23] target/arm: Make the v7-M Security State routines
  2019-06-15 15:43 ` [Qemu-devel] [PATCH v2 13/23] target/arm: Make the v7-M Security State routines Philippe Mathieu-Daudé
@ 2019-06-17 14:11   ` Alex Bennée
  0 siblings, 0 replies; 51+ messages in thread
From: Alex Bennée @ 2019-06-17 14:11 UTC (permalink / raw)
  To: qemu-arm; +Cc: Peter Maydell, Philippe Mathieu-Daudé, qemu-devel


Philippe Mathieu-Daudé <philmd@redhat.com> writes:

> The Security State helpers are now only called within v7m_helper.c.
> Remove them from "internals.h".
>
> Signed-off-by: Philippe Mathieu-Daudé <philmd@redhat.com>

This does seem a little round the houses, but whatever:

Reviewed-by: Alex Bennée <alex.bennee@linaro.org>


> ---
>  target/arm/internals.h  |  8 --------
>  target/arm/v7m_helper.c | 10 +++++-----
>  2 files changed, 5 insertions(+), 13 deletions(-)
>
> diff --git a/target/arm/internals.h b/target/arm/internals.h
> index 1d15af3f8b..fe9e4665e2 100644
> --- a/target/arm/internals.h
> +++ b/target/arm/internals.h
> @@ -1043,12 +1043,4 @@ bool pmsav8_mpu_lookup(CPUARMState *env, uint32_t address,
>                         int *prot, bool *is_subpage,
>                         ARMMMUFaultInfo *fi, uint32_t *mregion);
>
> -void write_v7m_control_spsel_for_secstate(CPUARMState *env,
> -                                          bool new_spsel,
> -                                          bool secstate);
> -
> -void write_v7m_control_spsel(CPUARMState *env, bool new_spsel);
> -
> -void switch_v7m_security_state(CPUARMState *env, bool new_secstate);
> -
>  #endif
> diff --git a/target/arm/v7m_helper.c b/target/arm/v7m_helper.c
> index b50bb98e06..aa6a08e326 100644
> --- a/target/arm/v7m_helper.c
> +++ b/target/arm/v7m_helper.c
> @@ -94,9 +94,9 @@ uint32_t HELPER(v7m_tt)(CPUARMState *env, uint32_t addr, uint32_t op)
>   * stack pointers if it is done for the CONTROL register for the current
>   * security state.
>   */
> -void write_v7m_control_spsel_for_secstate(CPUARMState *env,
> -                                          bool new_spsel,
> -                                          bool secstate)
> +static void write_v7m_control_spsel_for_secstate(CPUARMState *env,
> +                                                 bool new_spsel,
> +                                                 bool secstate)
>  {
>      bool old_is_psp = v7m_using_psp(env);
>
> @@ -121,13 +121,13 @@ void write_v7m_control_spsel_for_secstate(CPUARMState *env,
>   * Write to v7M CONTROL.SPSEL bit. This may change the current
>   * stack pointer between Main and Process stack pointers.
>   */
> -void write_v7m_control_spsel(CPUARMState *env, bool new_spsel)
> +static void write_v7m_control_spsel(CPUARMState *env, bool new_spsel)
>  {
>      write_v7m_control_spsel_for_secstate(env, new_spsel, env->v7m.secure);
>  }
>
>  /* Switch M profile security state between NS and S */
> -void switch_v7m_security_state(CPUARMState *env, bool new_secstate)
> +static void switch_v7m_security_state(CPUARMState *env, bool new_secstate)
>  {
>      uint32_t new_ss_msp, new_ss_psp;


--
Alex Bennée


^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [Qemu-devel] [Qemu-arm] [PATCH v2 14/23] target/arm: Move the DC ZVA helper into op_helper
  2019-06-15 15:43 ` [Qemu-devel] [PATCH v2 14/23] target/arm: Move the DC ZVA helper into op_helper Philippe Mathieu-Daudé
@ 2019-06-17 14:12   ` Alex Bennée
  0 siblings, 0 replies; 51+ messages in thread
From: Alex Bennée @ 2019-06-17 14:12 UTC (permalink / raw)
  To: qemu-arm
  Cc: Peter Maydell, Philippe Mathieu-Daudé,
	qemu-devel, Robert Bradford, Samuel Ortiz


Philippe Mathieu-Daudé <philmd@redhat.com> writes:

> From: Samuel Ortiz <sameo@linux.intel.com>
>
> Those helpers are a software implementation of the ARM v8 memory zeroing
> op code. They should be moved to the op helper file, which is going to
> eventually be built only when TCG is enabled.
>
> Signed-off-by: Samuel Ortiz <sameo@linux.intel.com>
> Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com>
> Reviewed-by: Robert Bradford <robert.bradford@intel.com>
> [PMD: Rebased]
> Signed-off-by: Philippe Mathieu-Daudé <philmd@redhat.com>

Reviewed-by: Alex Bennée <alex.bennee@linaro.org>

> ---
>  target/arm/helper.c    | 92 -----------------------------------------
>  target/arm/op_helper.c | 93 ++++++++++++++++++++++++++++++++++++++++++
>  2 files changed, 93 insertions(+), 92 deletions(-)
>
> diff --git a/target/arm/helper.c b/target/arm/helper.c
> index 24d88eef17..673ada1e86 100644
> --- a/target/arm/helper.c
> +++ b/target/arm/helper.c
> @@ -10674,98 +10674,6 @@ bool arm_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
>  #endif
>  }
>
> -void HELPER(dc_zva)(CPUARMState *env, uint64_t vaddr_in)
> -{
> -    /*
> -     * Implement DC ZVA, which zeroes a fixed-length block of memory.
> -     * Note that we do not implement the (architecturally mandated)
> -     * alignment fault for attempts to use this on Device memory
> -     * (which matches the usual QEMU behaviour of not implementing either
> -     * alignment faults or any memory attribute handling).
> -     */
> -
> -    ARMCPU *cpu = env_archcpu(env);
> -    uint64_t blocklen = 4 << cpu->dcz_blocksize;
> -    uint64_t vaddr = vaddr_in & ~(blocklen - 1);
> -
> -#ifndef CONFIG_USER_ONLY
> -    {
> -        /*
> -         * Slightly awkwardly, QEMU's TARGET_PAGE_SIZE may be less than
> -         * the block size so we might have to do more than one TLB lookup.
> -         * We know that in fact for any v8 CPU the page size is at least 4K
> -         * and the block size must be 2K or less, but TARGET_PAGE_SIZE is only
> -         * 1K as an artefact of legacy v5 subpage support being present in the
> -         * same QEMU executable. So in practice the hostaddr[] array has
> -         * two entries, given the current setting of TARGET_PAGE_BITS_MIN.
> -         */
> -        int maxidx = DIV_ROUND_UP(blocklen, TARGET_PAGE_SIZE);
> -        void *hostaddr[DIV_ROUND_UP(2 * KiB, 1 << TARGET_PAGE_BITS_MIN)];
> -        int try, i;
> -        unsigned mmu_idx = cpu_mmu_index(env, false);
> -        TCGMemOpIdx oi = make_memop_idx(MO_UB, mmu_idx);
> -
> -        assert(maxidx <= ARRAY_SIZE(hostaddr));
> -
> -        for (try = 0; try < 2; try++) {
> -
> -            for (i = 0; i < maxidx; i++) {
> -                hostaddr[i] = tlb_vaddr_to_host(env,
> -                                                vaddr + TARGET_PAGE_SIZE * i,
> -                                                1, mmu_idx);
> -                if (!hostaddr[i]) {
> -                    break;
> -                }
> -            }
> -            if (i == maxidx) {
> -                /*
> -                 * If it's all in the TLB it's fair game for just writing to;
> -                 * we know we don't need to update dirty status, etc.
> -                 */
> -                for (i = 0; i < maxidx - 1; i++) {
> -                    memset(hostaddr[i], 0, TARGET_PAGE_SIZE);
> -                }
> -                memset(hostaddr[i], 0, blocklen - (i * TARGET_PAGE_SIZE));
> -                return;
> -            }
> -            /*
> -             * OK, try a store and see if we can populate the tlb. This
> -             * might cause an exception if the memory isn't writable,
> -             * in which case we will longjmp out of here. We must for
> -             * this purpose use the actual register value passed to us
> -             * so that we get the fault address right.
> -             */
> -            helper_ret_stb_mmu(env, vaddr_in, 0, oi, GETPC());
> -            /* Now we can populate the other TLB entries, if any */
> -            for (i = 0; i < maxidx; i++) {
> -                uint64_t va = vaddr + TARGET_PAGE_SIZE * i;
> -                if (va != (vaddr_in & TARGET_PAGE_MASK)) {
> -                    helper_ret_stb_mmu(env, va, 0, oi, GETPC());
> -                }
> -            }
> -        }
> -
> -        /*
> -         * Slow path (probably attempt to do this to an I/O device or
> -         * similar, or clearing of a block of code we have translations
> -         * cached for). Just do a series of byte writes as the architecture
> -         * demands. It's not worth trying to use a cpu_physical_memory_map(),
> -         * memset(), unmap() sequence here because:
> -         *  + we'd need to account for the blocksize being larger than a page
> -         *  + the direct-RAM access case is almost always going to be dealt
> -         *    with in the fastpath code above, so there's no speed benefit
> -         *  + we would have to deal with the map returning NULL because the
> -         *    bounce buffer was in use
> -         */
> -        for (i = 0; i < blocklen; i++) {
> -            helper_ret_stb_mmu(env, vaddr + i, 0, oi, GETPC());
> -        }
> -    }
> -#else
> -    memset(g2h(vaddr), 0, blocklen);
> -#endif
> -}
> -
>  /* Note that signed overflow is undefined in C.  The following routines are
>     careful to use unsigned types where modulo arithmetic is required.
>     Failure to do so _will_ break on newer gcc.  */
> diff --git a/target/arm/op_helper.c b/target/arm/op_helper.c
> index db4254a67b..29b56039e5 100644
> --- a/target/arm/op_helper.c
> +++ b/target/arm/op_helper.c
> @@ -17,6 +17,7 @@
>   * License along with this library; if not, see <http://www.gnu.org/licenses/>.
>   */
>  #include "qemu/osdep.h"
> +#include "qemu/units.h"
>  #include "qemu/log.h"
>  #include "qemu/main-loop.h"
>  #include "cpu.h"
> @@ -1316,3 +1317,95 @@ uint32_t HELPER(ror_cc)(CPUARMState *env, uint32_t x, uint32_t i)
>          return ((uint32_t)x >> shift) | (x << (32 - shift));
>      }
>  }
> +
> +void HELPER(dc_zva)(CPUARMState *env, uint64_t vaddr_in)
> +{
> +    /*
> +     * Implement DC ZVA, which zeroes a fixed-length block of memory.
> +     * Note that we do not implement the (architecturally mandated)
> +     * alignment fault for attempts to use this on Device memory
> +     * (which matches the usual QEMU behaviour of not implementing either
> +     * alignment faults or any memory attribute handling).
> +     */
> +
> +    ARMCPU *cpu = env_archcpu(env);
> +    uint64_t blocklen = 4 << cpu->dcz_blocksize;
> +    uint64_t vaddr = vaddr_in & ~(blocklen - 1);
> +
> +#ifndef CONFIG_USER_ONLY
> +    {
> +        /*
> +         * Slightly awkwardly, QEMU's TARGET_PAGE_SIZE may be less than
> +         * the block size so we might have to do more than one TLB lookup.
> +         * We know that in fact for any v8 CPU the page size is at least 4K
> +         * and the block size must be 2K or less, but TARGET_PAGE_SIZE is only
> +         * 1K as an artefact of legacy v5 subpage support being present in the
> +         * same QEMU executable. So in practice the hostaddr[] array has
> +         * two entries, given the current setting of TARGET_PAGE_BITS_MIN.
> +         */
> +        int maxidx = DIV_ROUND_UP(blocklen, TARGET_PAGE_SIZE);
> +        void *hostaddr[DIV_ROUND_UP(2 * KiB, 1 << TARGET_PAGE_BITS_MIN)];
> +        int try, i;
> +        unsigned mmu_idx = cpu_mmu_index(env, false);
> +        TCGMemOpIdx oi = make_memop_idx(MO_UB, mmu_idx);
> +
> +        assert(maxidx <= ARRAY_SIZE(hostaddr));
> +
> +        for (try = 0; try < 2; try++) {
> +
> +            for (i = 0; i < maxidx; i++) {
> +                hostaddr[i] = tlb_vaddr_to_host(env,
> +                                                vaddr + TARGET_PAGE_SIZE * i,
> +                                                1, mmu_idx);
> +                if (!hostaddr[i]) {
> +                    break;
> +                }
> +            }
> +            if (i == maxidx) {
> +                /*
> +                 * If it's all in the TLB it's fair game for just writing to;
> +                 * we know we don't need to update dirty status, etc.
> +                 */
> +                for (i = 0; i < maxidx - 1; i++) {
> +                    memset(hostaddr[i], 0, TARGET_PAGE_SIZE);
> +                }
> +                memset(hostaddr[i], 0, blocklen - (i * TARGET_PAGE_SIZE));
> +                return;
> +            }
> +            /*
> +             * OK, try a store and see if we can populate the tlb. This
> +             * might cause an exception if the memory isn't writable,
> +             * in which case we will longjmp out of here. We must for
> +             * this purpose use the actual register value passed to us
> +             * so that we get the fault address right.
> +             */
> +            helper_ret_stb_mmu(env, vaddr_in, 0, oi, GETPC());
> +            /* Now we can populate the other TLB entries, if any */
> +            for (i = 0; i < maxidx; i++) {
> +                uint64_t va = vaddr + TARGET_PAGE_SIZE * i;
> +                if (va != (vaddr_in & TARGET_PAGE_MASK)) {
> +                    helper_ret_stb_mmu(env, va, 0, oi, GETPC());
> +                }
> +            }
> +        }
> +
> +        /*
> +         * Slow path (probably attempt to do this to an I/O device or
> +         * similar, or clearing of a block of code we have translations
> +         * cached for). Just do a series of byte writes as the architecture
> +         * demands. It's not worth trying to use a cpu_physical_memory_map(),
> +         * memset(), unmap() sequence here because:
> +         *  + we'd need to account for the blocksize being larger than a page
> +         *  + the direct-RAM access case is almost always going to be dealt
> +         *    with in the fastpath code above, so there's no speed benefit
> +         *  + we would have to deal with the map returning NULL because the
> +         *    bounce buffer was in use
> +         */
> +        for (i = 0; i < blocklen; i++) {
> +            helper_ret_stb_mmu(env, vaddr + i, 0, oi, GETPC());
> +        }
> +    }
> +#else
> +    memset(g2h(vaddr), 0, blocklen);
> +#endif
> +}


--
Alex Bennée


^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [Qemu-devel] [Qemu-arm] [PATCH v2 15/23] target/arm: Make ARM TLB filling routine static
  2019-06-15 15:43 ` [Qemu-devel] [PATCH v2 15/23] target/arm: Make ARM TLB filling routine static Philippe Mathieu-Daudé
@ 2019-06-17 14:16   ` Alex Bennée
  0 siblings, 0 replies; 51+ messages in thread
From: Alex Bennée @ 2019-06-17 14:16 UTC (permalink / raw)
  To: qemu-arm
  Cc: Peter Maydell, Philippe Mathieu-Daudé, qemu-devel, Samuel Ortiz


Philippe Mathieu-Daudé <philmd@redhat.com> writes:

> From: Samuel Ortiz <sameo@linux.intel.com>
>
> It's only used in op_helper.c, it does not need to be exported and
> moreover it should only be build when TCG is enabled.
>
> Signed-off-by: Samuel Ortiz <sameo@linux.intel.com>
> [PMD: Rebased]
> Signed-off-by: Philippe Mathieu-Daudé <philmd@redhat.com>
> ---
>  target/arm/helper.c    | 53 ---------------------------------------
>  target/arm/internals.h |  2 ++
>  target/arm/op_helper.c | 56 ++++++++++++++++++++++++++++++++++++++++++
>  3 files changed, 58 insertions(+), 53 deletions(-)
>
> diff --git a/target/arm/helper.c b/target/arm/helper.c
> index 673ada1e86..a4af02c984 100644
> --- a/target/arm/helper.c
> +++ b/target/arm/helper.c
> @@ -10621,59 +10621,6 @@ hwaddr arm_cpu_get_phys_page_attrs_debug(CPUState *cs, vaddr addr,
>
>  #endif
>
> -bool arm_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
> -                      MMUAccessType access_type, int mmu_idx,
> -                      bool probe, uintptr_t retaddr)
> -{
> -    ARMCPU *cpu = ARM_CPU(cs);
> -
> -#ifdef CONFIG_USER_ONLY
> -    cpu->env.exception.vaddress = address;
> -    if (access_type == MMU_INST_FETCH) {
> -        cs->exception_index = EXCP_PREFETCH_ABORT;
> -    } else {
> -        cs->exception_index = EXCP_DATA_ABORT;
> -    }
> -    cpu_loop_exit_restore(cs, retaddr);
> -#else
> -    hwaddr phys_addr;
> -    target_ulong page_size;
> -    int prot, ret;
> -    MemTxAttrs attrs = {};
> -    ARMMMUFaultInfo fi = {};
> -
> -    /*
> -     * Walk the page table and (if the mapping exists) add the page
> -     * to the TLB.  On success, return true.  Otherwise, if probing,
> -     * return false.  Otherwise populate fsr with ARM DFSR/IFSR fault
> -     * register format, and signal the fault.
> -     */
> -    ret = get_phys_addr(&cpu->env, address, access_type,
> -                        core_to_arm_mmu_idx(&cpu->env, mmu_idx),
> -                        &phys_addr, &attrs, &prot, &page_size, &fi,
> NULL);

Shouldn't we be moving the rest of the tlb filling code that gets
referred to here? Maybe we could keep it all together in tlb-helper.c?


> -    if (likely(!ret)) {
> -        /*
> -         * Map a single [sub]page. Regions smaller than our declared
> -         * target page size are handled specially, so for those we
> -         * pass in the exact addresses.
> -         */
> -        if (page_size >= TARGET_PAGE_SIZE) {
> -            phys_addr &= TARGET_PAGE_MASK;
> -            address &= TARGET_PAGE_MASK;
> -        }
> -        tlb_set_page_with_attrs(cs, address, phys_addr, attrs,
> -                                prot, mmu_idx, page_size);
> -        return true;
> -    } else if (probe) {
> -        return false;
> -    } else {
> -        /* now we have a real cpu fault */
> -        cpu_restore_state(cs, retaddr, true);
> -        arm_deliver_fault(cpu, address, access_type, mmu_idx, &fi);
> -    }
> -#endif
> -}
> -
>  /* Note that signed overflow is undefined in C.  The following routines are
>     careful to use unsigned types where modulo arithmetic is required.
>     Failure to do so _will_ break on newer gcc.  */
> diff --git a/target/arm/internals.h b/target/arm/internals.h
> index fe9e4665e2..37ca493635 100644
> --- a/target/arm/internals.h
> +++ b/target/arm/internals.h
> @@ -761,9 +761,11 @@ static inline bool arm_extabort_type(MemTxResult result)
>      return result != MEMTX_DECODE_ERROR;
>  }
>
> +#ifdef CONFIG_TCG
>  bool arm_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
>                        MMUAccessType access_type, int mmu_idx,
>                        bool probe, uintptr_t retaddr);
> +#endif
>
>  void arm_deliver_fault(ARMCPU *cpu, vaddr addr, MMUAccessType access_type,
>                         int mmu_idx, ARMMMUFaultInfo *fi) QEMU_NORETURN;
> diff --git a/target/arm/op_helper.c b/target/arm/op_helper.c
> index 29b56039e5..e43c99ebf0 100644
> --- a/target/arm/op_helper.c
> +++ b/target/arm/op_helper.c
> @@ -179,6 +179,62 @@ void arm_deliver_fault(ARMCPU *cpu, vaddr addr, MMUAccessType access_type,
>      env->exception.fsr = fsr;
>      raise_exception(env, exc, syn, target_el);
>  }
> +#endif
> +
> +bool arm_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
> +                      MMUAccessType access_type, int mmu_idx,
> +                      bool probe, uintptr_t retaddr)
> +{
> +    ARMCPU *cpu = ARM_CPU(cs);
> +
> +#ifdef CONFIG_USER_ONLY
> +    cpu->env.exception.vaddress = address;
> +    if (access_type == MMU_INST_FETCH) {
> +        cs->exception_index = EXCP_PREFETCH_ABORT;
> +    } else {
> +        cs->exception_index = EXCP_DATA_ABORT;
> +    }
> +    cpu_loop_exit_restore(cs, retaddr);
> +#else
> +    hwaddr phys_addr;
> +    target_ulong page_size;
> +    int prot, ret;
> +    MemTxAttrs attrs = {};
> +    ARMMMUFaultInfo fi = {};
> +
> +    /*
> +     * Walk the page table and (if the mapping exists) add the page
> +     * to the TLB.  On success, return true.  Otherwise, if probing,
> +     * return false.  Otherwise populate fsr with ARM DFSR/IFSR fault
> +     * register format, and signal the fault.
> +     */
> +    ret = get_phys_addr(&cpu->env, address, access_type,
> +                        core_to_arm_mmu_idx(&cpu->env, mmu_idx),
> +                        &phys_addr, &attrs, &prot, &page_size, &fi, NULL);
> +    if (likely(!ret)) {
> +        /*
> +         * Map a single [sub]page. Regions smaller than our declared
> +         * target page size are handled specially, so for those we
> +         * pass in the exact addresses.
> +         */
> +        if (page_size >= TARGET_PAGE_SIZE) {
> +            phys_addr &= TARGET_PAGE_MASK;
> +            address &= TARGET_PAGE_MASK;
> +        }
> +        tlb_set_page_with_attrs(cs, address, phys_addr, attrs,
> +                                prot, mmu_idx, page_size);
> +        return true;
> +    } else if (probe) {
> +        return false;
> +    } else {
> +        /* now we have a real cpu fault */
> +        cpu_restore_state(cs, retaddr, true);
> +        arm_deliver_fault(cpu, address, access_type, mmu_idx, &fi);
> +    }
> +#endif
> +}
> +
> +#if !defined(CONFIG_USER_ONLY)
>
>  /* Raise a data fault alignment exception for the specified virtual address */
>  void arm_cpu_do_unaligned_access(CPUState *cs, vaddr vaddr,


--
Alex Bennée


^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [Qemu-devel] [Qemu-arm] [PATCH v2 16/23] target/arm: Make arm_deliver_fault() static
  2019-06-15 15:43 ` [Qemu-devel] [PATCH v2 16/23] target/arm: Make arm_deliver_fault() static Philippe Mathieu-Daudé
@ 2019-06-17 14:19   ` Alex Bennée
  0 siblings, 0 replies; 51+ messages in thread
From: Alex Bennée @ 2019-06-17 14:19 UTC (permalink / raw)
  To: qemu-arm; +Cc: Peter Maydell, Philippe Mathieu-Daudé, qemu-devel


Philippe Mathieu-Daudé <philmd@redhat.com> writes:

> This function is now only called within op_helper.c.
>
> Signed-off-by: Philippe Mathieu-Daudé <philmd@redhat.com>

Reviewed-by: Alex Bennée <alex.bennee@linaro.org>

(although if we move the tlb related bits that might be different)

> ---
>  target/arm/internals.h | 3 ---
>  target/arm/op_helper.c | 5 +++--
>  2 files changed, 3 insertions(+), 5 deletions(-)
>
> diff --git a/target/arm/internals.h b/target/arm/internals.h
> index 37ca493635..06e676bf62 100644
> --- a/target/arm/internals.h
> +++ b/target/arm/internals.h
> @@ -767,9 +767,6 @@ bool arm_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
>                        bool probe, uintptr_t retaddr);
>  #endif
>
> -void arm_deliver_fault(ARMCPU *cpu, vaddr addr, MMUAccessType access_type,
> -                       int mmu_idx, ARMMMUFaultInfo *fi) QEMU_NORETURN;
> -
>  /* Return true if the stage 1 translation regime is using LPAE format page
>   * tables */
>  bool arm_s1_regime_using_lpae_format(CPUARMState *env, ARMMMUIdx mmu_idx);
> diff --git a/target/arm/op_helper.c b/target/arm/op_helper.c
> index e43c99ebf0..63bce32810 100644
> --- a/target/arm/op_helper.c
> +++ b/target/arm/op_helper.c
> @@ -127,8 +127,9 @@ static inline uint32_t merge_syn_data_abort(uint32_t template_syn,
>      return syn;
>  }
>
> -void arm_deliver_fault(ARMCPU *cpu, vaddr addr, MMUAccessType access_type,
> -                       int mmu_idx, ARMMMUFaultInfo *fi)
> +static void QEMU_NORETURN arm_deliver_fault(ARMCPU *cpu, vaddr addr,
> +                                            MMUAccessType access_type,
> +                                            int mmu_idx, ARMMMUFaultInfo *fi)
>  {
>      CPUARMState *env = &cpu->env;
>      int target_el;


--
Alex Bennée


^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [Qemu-devel] [Qemu-arm] [PATCH v2 17/23] target/arm: Fix coding style issues
  2019-06-15 15:43 ` [Qemu-devel] [PATCH v2 17/23] target/arm: Fix coding style issues Philippe Mathieu-Daudé
@ 2019-06-17 14:20   ` Alex Bennée
  0 siblings, 0 replies; 51+ messages in thread
From: Alex Bennée @ 2019-06-17 14:20 UTC (permalink / raw)
  To: qemu-arm; +Cc: Peter Maydell, Philippe Mathieu-Daudé, qemu-devel


Philippe Mathieu-Daudé <philmd@redhat.com> writes:

> Since we'll move this code around, fix its style first.
>
> Signed-off-by: Philippe Mathieu-Daudé <philmd@redhat.com>

Reviewed-by: Alex Bennée <alex.bennee@linaro.org>

> ---
>  target/arm/translate.c | 11 ++++++-----
>  1 file changed, 6 insertions(+), 5 deletions(-)
>
> diff --git a/target/arm/translate.c b/target/arm/translate.c
> index c274c8b460..d0ab3e27e6 100644
> --- a/target/arm/translate.c
> +++ b/target/arm/translate.c
> @@ -9179,7 +9179,7 @@ static void disas_arm_insn(DisasContext *s, unsigned int insn)
>                  loaded_base = 0;
>                  loaded_var = NULL;
>                  n = 0;
> -                for(i=0;i<16;i++) {
> +                for (i = 0; i < 16; i++) {
>                      if (insn & (1 << i))
>                          n++;
>                  }
> @@ -9202,7 +9202,7 @@ static void disas_arm_insn(DisasContext *s, unsigned int insn)
>                      }
>                  }
>                  j = 0;
> -                for(i=0;i<16;i++) {
> +                for (i = 0; i < 16; i++) {
>                      if (insn & (1 << i)) {
>                          if (is_load) {
>                              /* load */
> @@ -12427,12 +12427,13 @@ void arm_cpu_dump_state(CPUState *cs, FILE *f, int flags)
>          return;
>      }
>
> -    for(i=0;i<16;i++) {
> +    for (i = 0; i < 16; i++) {
>          qemu_fprintf(f, "R%02d=%08x", i, env->regs[i]);
> -        if ((i % 4) == 3)
> +        if ((i % 4) == 3) {
>              qemu_fprintf(f, "\n");
> -        else
> +        } else {
>              qemu_fprintf(f, " ");
> +        }
>      }
>
>      if (arm_feature(env, ARM_FEATURE_M)) {


--
Alex Bennée


^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [Qemu-devel] [Qemu-arm] [PATCH v2 18/23] target/arm: Move CPU state dumping routines to helper.c
  2019-06-15 15:43 ` [Qemu-devel] [PATCH v2 18/23] target/arm: Move CPU state dumping routines to helper.c Philippe Mathieu-Daudé
@ 2019-06-17 14:41   ` Alex Bennée
  2019-06-17 14:45     ` Philippe Mathieu-Daudé
  2019-06-17 14:52     ` Peter Maydell
  0 siblings, 2 replies; 51+ messages in thread
From: Alex Bennée @ 2019-06-17 14:41 UTC (permalink / raw)
  To: qemu-arm
  Cc: Peter Maydell, Philippe Mathieu-Daudé,
	qemu-devel, Robert Bradford, Samuel Ortiz


Philippe Mathieu-Daudé <philmd@redhat.com> writes:

> From: Samuel Ortiz <sameo@linux.intel.com>
>
> They're not TCG specific and should be living the generic helper file
> instead.
>
> Signed-off-by: Samuel Ortiz <sameo@linux.intel.com>
> Reviewed-by: Robert Bradford <robert.bradford@intel.com>
> [PMD: Rebased]
> Signed-off-by: Philippe Mathieu-Daudé <philmd@redhat.com>
> ---
>  target/arm/helper.c        | 214
> +++++++++++++++++++++++++++++++++++++

Hmm so helper is a mix of non-TCG and TCG bits whereas helper-a64.c is
basically just TCG helpers. It makes me wonder if we are breaking a
convention here as helper.c is traditionally only TCG helpers.

It feels like there should be different file that is unambiguously used
for both TCG and KVM based workloads where things like the cpu dump code
can live.

>  target/arm/internals.h     |   8 ++
>  target/arm/translate-a64.c | 127 ----------------------
>  target/arm/translate.c     |  87 ---------------
>  target/arm/translate.h     |   5 -
>  5 files changed, 222 insertions(+), 219 deletions(-)
>
> diff --git a/target/arm/helper.c b/target/arm/helper.c
> index a4af02c984..8c32b2bc0d 100644
> --- a/target/arm/helper.c
> +++ b/target/arm/helper.c
> @@ -11293,4 +11293,218 @@ void aarch64_sve_change_el(CPUARMState *env, int old_el,
>          aarch64_sve_narrow_vq(env, new_len + 1);
>      }
>  }
> +
> +void aarch64_cpu_dump_state(CPUState *cs, FILE *f, int flags)
> +{
> +    ARMCPU *cpu = ARM_CPU(cs);
> +    CPUARMState *env = &cpu->env;
> +    uint32_t psr = pstate_read(env);
> +    int i;
> +    int el = arm_current_el(env);
> +    const char *ns_status;
> +
> +    qemu_fprintf(f, " PC=%016" PRIx64 " ", env->pc);
> +    for (i = 0; i < 32; i++) {
> +        if (i == 31) {
> +            qemu_fprintf(f, " SP=%016" PRIx64 "\n", env->xregs[i]);
> +        } else {
> +            qemu_fprintf(f, "X%02d=%016" PRIx64 "%s", i, env->xregs[i],
> +                         (i + 2) % 3 ? " " : "\n");
> +        }
> +    }
> +
> +    if (arm_feature(env, ARM_FEATURE_EL3) && el != 3) {
> +        ns_status = env->cp15.scr_el3 & SCR_NS ? "NS " : "S ";
> +    } else {
> +        ns_status = "";
> +    }
> +    qemu_fprintf(f, "PSTATE=%08x %c%c%c%c %sEL%d%c",
> +                 psr,
> +                 psr & PSTATE_N ? 'N' : '-',
> +                 psr & PSTATE_Z ? 'Z' : '-',
> +                 psr & PSTATE_C ? 'C' : '-',
> +                 psr & PSTATE_V ? 'V' : '-',
> +                 ns_status,
> +                 el,
> +                 psr & PSTATE_SP ? 'h' : 't');
> +
> +    if (cpu_isar_feature(aa64_bti, cpu)) {
> +        qemu_fprintf(f, "  BTYPE=%d", (psr & PSTATE_BTYPE) >> 10);
> +    }
> +    if (!(flags & CPU_DUMP_FPU)) {
> +        qemu_fprintf(f, "\n");
> +        return;
> +    }
> +    if (fp_exception_el(env, el) != 0) {
> +        qemu_fprintf(f, "    FPU disabled\n");
> +        return;
> +    }
> +    qemu_fprintf(f, "     FPCR=%08x FPSR=%08x\n",
> +                 vfp_get_fpcr(env), vfp_get_fpsr(env));
> +
> +    if (cpu_isar_feature(aa64_sve, cpu) && sve_exception_el(env, el) == 0) {
> +        int j, zcr_len = sve_zcr_len_for_el(env, el);
> +
> +        for (i = 0; i <= FFR_PRED_NUM; i++) {
> +            bool eol;
> +            if (i == FFR_PRED_NUM) {
> +                qemu_fprintf(f, "FFR=");
> +                /* It's last, so end the line.  */
> +                eol = true;
> +            } else {
> +                qemu_fprintf(f, "P%02d=", i);
> +                switch (zcr_len) {
> +                case 0:
> +                    eol = i % 8 == 7;
> +                    break;
> +                case 1:
> +                    eol = i % 6 == 5;
> +                    break;
> +                case 2:
> +                case 3:
> +                    eol = i % 3 == 2;
> +                    break;
> +                default:
> +                    /* More than one quadword per predicate.  */
> +                    eol = true;
> +                    break;
> +                }
> +            }
> +            for (j = zcr_len / 4; j >= 0; j--) {
> +                int digits;
> +                if (j * 4 + 4 <= zcr_len + 1) {
> +                    digits = 16;
> +                } else {
> +                    digits = (zcr_len % 4 + 1) * 4;
> +                }
> +                qemu_fprintf(f, "%0*" PRIx64 "%s", digits,
> +                             env->vfp.pregs[i].p[j],
> +                             j ? ":" : eol ? "\n" : " ");
> +            }
> +        }
> +
> +        for (i = 0; i < 32; i++) {
> +            if (zcr_len == 0) {
> +                qemu_fprintf(f, "Z%02d=%016" PRIx64 ":%016" PRIx64 "%s",
> +                             i, env->vfp.zregs[i].d[1],
> +                             env->vfp.zregs[i].d[0], i & 1 ? "\n" : " ");
> +            } else if (zcr_len == 1) {
> +                qemu_fprintf(f, "Z%02d=%016" PRIx64 ":%016" PRIx64
> +                             ":%016" PRIx64 ":%016" PRIx64 "\n",
> +                             i, env->vfp.zregs[i].d[3], env->vfp.zregs[i].d[2],
> +                             env->vfp.zregs[i].d[1], env->vfp.zregs[i].d[0]);
> +            } else {
> +                for (j = zcr_len; j >= 0; j--) {
> +                    bool odd = (zcr_len - j) % 2 != 0;
> +                    if (j == zcr_len) {
> +                        qemu_fprintf(f, "Z%02d[%x-%x]=", i, j, j - 1);
> +                    } else if (!odd) {
> +                        if (j > 0) {
> +                            qemu_fprintf(f, "   [%x-%x]=", j, j - 1);
> +                        } else {
> +                            qemu_fprintf(f, "     [%x]=", j);
> +                        }
> +                    }
> +                    qemu_fprintf(f, "%016" PRIx64 ":%016" PRIx64 "%s",
> +                                 env->vfp.zregs[i].d[j * 2 + 1],
> +                                 env->vfp.zregs[i].d[j * 2],
> +                                 odd || j == 0 ? "\n" : ":");
> +                }
> +            }
> +        }
> +    } else {
> +        for (i = 0; i < 32; i++) {
> +            uint64_t *q = aa64_vfp_qreg(env, i);
> +            qemu_fprintf(f, "Q%02d=%016" PRIx64 ":%016" PRIx64 "%s",
> +                         i, q[1], q[0], (i & 1 ? "\n" : " "));
> +        }
> +    }
> +}
>  #endif
> +
> +void arm_cpu_dump_state(CPUState *cs, FILE *f, int flags)
> +{
> +    ARMCPU *cpu = ARM_CPU(cs);
> +    CPUARMState *env = &cpu->env;
> +    int i;
> +
> +    if (is_a64(env)) {
> +        aarch64_cpu_dump_state(cs, f, flags);
> +        return;
> +    }
> +
> +    for (i = 0; i < 16; i++) {
> +        qemu_fprintf(f, "R%02d=%08x", i, env->regs[i]);
> +        if ((i % 4) == 3) {
> +            qemu_fprintf(f, "\n");
> +        } else {
> +            qemu_fprintf(f, " ");
> +        }
> +    }
> +
> +    if (arm_feature(env, ARM_FEATURE_M)) {
> +        uint32_t xpsr = xpsr_read(env);
> +        const char *mode;
> +        const char *ns_status = "";
> +
> +        if (arm_feature(env, ARM_FEATURE_M_SECURITY)) {
> +            ns_status = env->v7m.secure ? "S " : "NS ";
> +        }
> +
> +        if (xpsr & XPSR_EXCP) {
> +            mode = "handler";
> +        } else {
> +            if (env->v7m.control[env->v7m.secure] & R_V7M_CONTROL_NPRIV_MASK) {
> +                mode = "unpriv-thread";
> +            } else {
> +                mode = "priv-thread";
> +            }
> +        }
> +
> +        qemu_fprintf(f, "XPSR=%08x %c%c%c%c %c %s%s\n",
> +                     xpsr,
> +                     xpsr & XPSR_N ? 'N' : '-',
> +                     xpsr & XPSR_Z ? 'Z' : '-',
> +                     xpsr & XPSR_C ? 'C' : '-',
> +                     xpsr & XPSR_V ? 'V' : '-',
> +                     xpsr & XPSR_T ? 'T' : 'A',
> +                     ns_status,
> +                     mode);
> +    } else {
> +        uint32_t psr = cpsr_read(env);
> +        const char *ns_status = "";
> +
> +        if (arm_feature(env, ARM_FEATURE_EL3) &&
> +            (psr & CPSR_M) != ARM_CPU_MODE_MON) {
> +            ns_status = env->cp15.scr_el3 & SCR_NS ? "NS " : "S ";
> +        }
> +
> +        qemu_fprintf(f, "PSR=%08x %c%c%c%c %c %s%s%d\n",
> +                     psr,
> +                     psr & CPSR_N ? 'N' : '-',
> +                     psr & CPSR_Z ? 'Z' : '-',
> +                     psr & CPSR_C ? 'C' : '-',
> +                     psr & CPSR_V ? 'V' : '-',
> +                     psr & CPSR_T ? 'T' : 'A',
> +                     ns_status,
> +                     aarch32_mode_name(psr), (psr & 0x10) ? 32 : 26);
> +    }
> +
> +    if (flags & CPU_DUMP_FPU) {
> +        int numvfpregs = 0;
> +        if (arm_feature(env, ARM_FEATURE_VFP)) {
> +            numvfpregs += 16;
> +        }
> +        if (arm_feature(env, ARM_FEATURE_VFP3)) {
> +            numvfpregs += 16;
> +        }
> +        for (i = 0; i < numvfpregs; i++) {
> +            uint64_t v = *aa32_vfp_dreg(env, i);
> +            qemu_fprintf(f, "s%02d=%08x s%02d=%08x d%02d=%016" PRIx64 "\n",
> +                         i * 2, (uint32_t)v,
> +                         i * 2 + 1, (uint32_t)(v >> 32),
> +                         i, v);
> +        }
> +        qemu_fprintf(f, "FPSCR: %08x\n", vfp_get_fpscr(env));
> +    }
> +}
> diff --git a/target/arm/internals.h b/target/arm/internals.h
> index 06e676bf62..56281d8ece 100644
> --- a/target/arm/internals.h
> +++ b/target/arm/internals.h
> @@ -1042,4 +1042,12 @@ bool pmsav8_mpu_lookup(CPUARMState *env, uint32_t address,
>                         int *prot, bool *is_subpage,
>                         ARMMMUFaultInfo *fi, uint32_t *mregion);
>
> +#ifdef TARGET_AARCH64
> +void aarch64_cpu_dump_state(CPUState *cs, FILE *f, int flags);
> +#else
> +static inline void aarch64_cpu_dump_state(CPUState *cs, FILE *f, int flags)
> +{
> +}
> +#endif
> +
>  #endif
> diff --git a/target/arm/translate-a64.c b/target/arm/translate-a64.c
> index ae739f6575..8abe1f0e4f 100644
> --- a/target/arm/translate-a64.c
> +++ b/target/arm/translate-a64.c
> @@ -152,133 +152,6 @@ static void set_btype(DisasContext *s, int val)
>      s->btype = -1;
>  }
>
> -void aarch64_cpu_dump_state(CPUState *cs, FILE *f, int flags)
> -{
> -    ARMCPU *cpu = ARM_CPU(cs);
> -    CPUARMState *env = &cpu->env;
> -    uint32_t psr = pstate_read(env);
> -    int i;
> -    int el = arm_current_el(env);
> -    const char *ns_status;
> -
> -    qemu_fprintf(f, " PC=%016" PRIx64 " ", env->pc);
> -    for (i = 0; i < 32; i++) {
> -        if (i == 31) {
> -            qemu_fprintf(f, " SP=%016" PRIx64 "\n", env->xregs[i]);
> -        } else {
> -            qemu_fprintf(f, "X%02d=%016" PRIx64 "%s", i, env->xregs[i],
> -                         (i + 2) % 3 ? " " : "\n");
> -        }
> -    }
> -
> -    if (arm_feature(env, ARM_FEATURE_EL3) && el != 3) {
> -        ns_status = env->cp15.scr_el3 & SCR_NS ? "NS " : "S ";
> -    } else {
> -        ns_status = "";
> -    }
> -    qemu_fprintf(f, "PSTATE=%08x %c%c%c%c %sEL%d%c",
> -                 psr,
> -                 psr & PSTATE_N ? 'N' : '-',
> -                 psr & PSTATE_Z ? 'Z' : '-',
> -                 psr & PSTATE_C ? 'C' : '-',
> -                 psr & PSTATE_V ? 'V' : '-',
> -                 ns_status,
> -                 el,
> -                 psr & PSTATE_SP ? 'h' : 't');
> -
> -    if (cpu_isar_feature(aa64_bti, cpu)) {
> -        qemu_fprintf(f, "  BTYPE=%d", (psr & PSTATE_BTYPE) >> 10);
> -    }
> -    if (!(flags & CPU_DUMP_FPU)) {
> -        qemu_fprintf(f, "\n");
> -        return;
> -    }
> -    if (fp_exception_el(env, el) != 0) {
> -        qemu_fprintf(f, "    FPU disabled\n");
> -        return;
> -    }
> -    qemu_fprintf(f, "     FPCR=%08x FPSR=%08x\n",
> -                 vfp_get_fpcr(env), vfp_get_fpsr(env));
> -
> -    if (cpu_isar_feature(aa64_sve, cpu) && sve_exception_el(env, el) == 0) {
> -        int j, zcr_len = sve_zcr_len_for_el(env, el);
> -
> -        for (i = 0; i <= FFR_PRED_NUM; i++) {
> -            bool eol;
> -            if (i == FFR_PRED_NUM) {
> -                qemu_fprintf(f, "FFR=");
> -                /* It's last, so end the line.  */
> -                eol = true;
> -            } else {
> -                qemu_fprintf(f, "P%02d=", i);
> -                switch (zcr_len) {
> -                case 0:
> -                    eol = i % 8 == 7;
> -                    break;
> -                case 1:
> -                    eol = i % 6 == 5;
> -                    break;
> -                case 2:
> -                case 3:
> -                    eol = i % 3 == 2;
> -                    break;
> -                default:
> -                    /* More than one quadword per predicate.  */
> -                    eol = true;
> -                    break;
> -                }
> -            }
> -            for (j = zcr_len / 4; j >= 0; j--) {
> -                int digits;
> -                if (j * 4 + 4 <= zcr_len + 1) {
> -                    digits = 16;
> -                } else {
> -                    digits = (zcr_len % 4 + 1) * 4;
> -                }
> -                qemu_fprintf(f, "%0*" PRIx64 "%s", digits,
> -                             env->vfp.pregs[i].p[j],
> -                             j ? ":" : eol ? "\n" : " ");
> -            }
> -        }
> -
> -        for (i = 0; i < 32; i++) {
> -            if (zcr_len == 0) {
> -                qemu_fprintf(f, "Z%02d=%016" PRIx64 ":%016" PRIx64 "%s",
> -                             i, env->vfp.zregs[i].d[1],
> -                             env->vfp.zregs[i].d[0], i & 1 ? "\n" : " ");
> -            } else if (zcr_len == 1) {
> -                qemu_fprintf(f, "Z%02d=%016" PRIx64 ":%016" PRIx64
> -                             ":%016" PRIx64 ":%016" PRIx64 "\n",
> -                             i, env->vfp.zregs[i].d[3], env->vfp.zregs[i].d[2],
> -                             env->vfp.zregs[i].d[1], env->vfp.zregs[i].d[0]);
> -            } else {
> -                for (j = zcr_len; j >= 0; j--) {
> -                    bool odd = (zcr_len - j) % 2 != 0;
> -                    if (j == zcr_len) {
> -                        qemu_fprintf(f, "Z%02d[%x-%x]=", i, j, j - 1);
> -                    } else if (!odd) {
> -                        if (j > 0) {
> -                            qemu_fprintf(f, "   [%x-%x]=", j, j - 1);
> -                        } else {
> -                            qemu_fprintf(f, "     [%x]=", j);
> -                        }
> -                    }
> -                    qemu_fprintf(f, "%016" PRIx64 ":%016" PRIx64 "%s",
> -                                 env->vfp.zregs[i].d[j * 2 + 1],
> -                                 env->vfp.zregs[i].d[j * 2],
> -                                 odd || j == 0 ? "\n" : ":");
> -                }
> -            }
> -        }
> -    } else {
> -        for (i = 0; i < 32; i++) {
> -            uint64_t *q = aa64_vfp_qreg(env, i);
> -            qemu_fprintf(f, "Q%02d=%016" PRIx64 ":%016" PRIx64 "%s",
> -                         i, q[1], q[0], (i & 1 ? "\n" : " "));
> -        }
> -    }
> -}
> -
>  void gen_a64_set_pc_im(uint64_t val)
>  {
>      tcg_gen_movi_i64(cpu_pc, val);
> diff --git a/target/arm/translate.c b/target/arm/translate.c
> index d0ab3e27e6..1e50627690 100644
> --- a/target/arm/translate.c
> +++ b/target/arm/translate.c
> @@ -12416,93 +12416,6 @@ void gen_intermediate_code(CPUState *cpu, TranslationBlock *tb, int max_insns)
>      translator_loop(ops, &dc.base, cpu, tb, max_insns);
>  }
>
> -void arm_cpu_dump_state(CPUState *cs, FILE *f, int flags)
> -{
> -    ARMCPU *cpu = ARM_CPU(cs);
> -    CPUARMState *env = &cpu->env;
> -    int i;
> -
> -    if (is_a64(env)) {
> -        aarch64_cpu_dump_state(cs, f, flags);
> -        return;
> -    }
> -
> -    for (i = 0; i < 16; i++) {
> -        qemu_fprintf(f, "R%02d=%08x", i, env->regs[i]);
> -        if ((i % 4) == 3) {
> -            qemu_fprintf(f, "\n");
> -        } else {
> -            qemu_fprintf(f, " ");
> -        }
> -    }
> -
> -    if (arm_feature(env, ARM_FEATURE_M)) {
> -        uint32_t xpsr = xpsr_read(env);
> -        const char *mode;
> -        const char *ns_status = "";
> -
> -        if (arm_feature(env, ARM_FEATURE_M_SECURITY)) {
> -            ns_status = env->v7m.secure ? "S " : "NS ";
> -        }
> -
> -        if (xpsr & XPSR_EXCP) {
> -            mode = "handler";
> -        } else {
> -            if (env->v7m.control[env->v7m.secure] & R_V7M_CONTROL_NPRIV_MASK) {
> -                mode = "unpriv-thread";
> -            } else {
> -                mode = "priv-thread";
> -            }
> -        }
> -
> -        qemu_fprintf(f, "XPSR=%08x %c%c%c%c %c %s%s\n",
> -                     xpsr,
> -                     xpsr & XPSR_N ? 'N' : '-',
> -                     xpsr & XPSR_Z ? 'Z' : '-',
> -                     xpsr & XPSR_C ? 'C' : '-',
> -                     xpsr & XPSR_V ? 'V' : '-',
> -                     xpsr & XPSR_T ? 'T' : 'A',
> -                     ns_status,
> -                     mode);
> -    } else {
> -        uint32_t psr = cpsr_read(env);
> -        const char *ns_status = "";
> -
> -        if (arm_feature(env, ARM_FEATURE_EL3) &&
> -            (psr & CPSR_M) != ARM_CPU_MODE_MON) {
> -            ns_status = env->cp15.scr_el3 & SCR_NS ? "NS " : "S ";
> -        }
> -
> -        qemu_fprintf(f, "PSR=%08x %c%c%c%c %c %s%s%d\n",
> -                     psr,
> -                     psr & CPSR_N ? 'N' : '-',
> -                     psr & CPSR_Z ? 'Z' : '-',
> -                     psr & CPSR_C ? 'C' : '-',
> -                     psr & CPSR_V ? 'V' : '-',
> -                     psr & CPSR_T ? 'T' : 'A',
> -                     ns_status,
> -                     aarch32_mode_name(psr), (psr & 0x10) ? 32 : 26);
> -    }
> -
> -    if (flags & CPU_DUMP_FPU) {
> -        int numvfpregs = 0;
> -        if (arm_feature(env, ARM_FEATURE_VFP)) {
> -            numvfpregs += 16;
> -        }
> -        if (arm_feature(env, ARM_FEATURE_VFP3)) {
> -            numvfpregs += 16;
> -        }
> -        for (i = 0; i < numvfpregs; i++) {
> -            uint64_t v = *aa32_vfp_dreg(env, i);
> -            qemu_fprintf(f, "s%02d=%08x s%02d=%08x d%02d=%016" PRIx64 "\n",
> -                         i * 2, (uint32_t)v,
> -                         i * 2 + 1, (uint32_t)(v >> 32),
> -                         i, v);
> -        }
> -        qemu_fprintf(f, "FPSCR: %08x\n", vfp_get_fpscr(env));
> -    }
> -}
> -
>  void restore_state_to_opc(CPUARMState *env, TranslationBlock *tb,
>                            target_ulong *data)
>  {
> diff --git a/target/arm/translate.h b/target/arm/translate.h
> index dc06dce767..1dd3ac0a41 100644
> --- a/target/arm/translate.h
> +++ b/target/arm/translate.h
> @@ -169,7 +169,6 @@ static inline void disas_set_insn_syndrome(DisasContext *s, uint32_t syn)
>  #ifdef TARGET_AARCH64
>  void a64_translate_init(void);
>  void gen_a64_set_pc_im(uint64_t val);
> -void aarch64_cpu_dump_state(CPUState *cs, FILE *f, int flags);
>  extern const TranslatorOps aarch64_translator_ops;
>  #else
>  static inline void a64_translate_init(void)
> @@ -179,10 +178,6 @@ static inline void a64_translate_init(void)
>  static inline void gen_a64_set_pc_im(uint64_t val)
>  {
>  }
> -
> -static inline void aarch64_cpu_dump_state(CPUState *cs, FILE *f, int flags)
> -{
> -}
>  #endif
>
>  void arm_test_cc(DisasCompare *cmp, int cc);


--
Alex Bennée


^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [Qemu-devel] [Qemu-arm] [PATCH v2 18/23] target/arm: Move CPU state dumping routines to helper.c
  2019-06-17 14:41   ` [Qemu-devel] [Qemu-arm] " Alex Bennée
@ 2019-06-17 14:45     ` Philippe Mathieu-Daudé
  2019-06-17 14:52     ` Peter Maydell
  1 sibling, 0 replies; 51+ messages in thread
From: Philippe Mathieu-Daudé @ 2019-06-17 14:45 UTC (permalink / raw)
  To: Alex Bennée, qemu-arm
  Cc: Peter Maydell, qemu-devel, Robert Bradford, Samuel Ortiz

On 6/17/19 4:41 PM, Alex Bennée wrote:
> 
> Philippe Mathieu-Daudé <philmd@redhat.com> writes:
> 
>> From: Samuel Ortiz <sameo@linux.intel.com>
>>
>> They're not TCG specific and should be living the generic helper file
>> instead.
>>
>> Signed-off-by: Samuel Ortiz <sameo@linux.intel.com>
>> Reviewed-by: Robert Bradford <robert.bradford@intel.com>
>> [PMD: Rebased]
>> Signed-off-by: Philippe Mathieu-Daudé <philmd@redhat.com>
>> ---
>>  target/arm/helper.c        | 214
>> +++++++++++++++++++++++++++++++++++++
> 
> Hmm so helper is a mix of non-TCG and TCG bits whereas helper-a64.c is
> basically just TCG helpers. It makes me wonder if we are breaking a
> convention here as helper.c is traditionally only TCG helpers.
> 
> It feels like there should be different file that is unambiguously used
> for both TCG and KVM based workloads where things like the cpu dump code
> can live.

Good idea. What about target/arm/arch_dump.c?

>>  target/arm/internals.h     |   8 ++
>>  target/arm/translate-a64.c | 127 ----------------------
>>  target/arm/translate.c     |  87 ---------------
>>  target/arm/translate.h     |   5 -
>>  5 files changed, 222 insertions(+), 219 deletions(-)


^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [Qemu-devel] [Qemu-arm] [PATCH v2 19/23] target/arm: Move watchpoints APIs to helper.c
  2019-06-15 15:43 ` [Qemu-devel] [PATCH v2 19/23] target/arm: Move watchpoints APIs " Philippe Mathieu-Daudé
@ 2019-06-17 14:46   ` Alex Bennée
  0 siblings, 0 replies; 51+ messages in thread
From: Alex Bennée @ 2019-06-17 14:46 UTC (permalink / raw)
  To: qemu-arm
  Cc: Peter Maydell, Philippe Mathieu-Daudé,
	qemu-devel, Robert Bradford, Samuel Ortiz


Philippe Mathieu-Daudé <philmd@redhat.com> writes:

> From: Samuel Ortiz <sameo@linux.intel.com>
>
> Here again, those APIs are not TCG dependent and can move to the always
> built helper.c.

Are you sure about that?

Under KVM BP and WP exceptions only ever make there way to QEMU when
guest debug is in effect. At which point it goes through
kvm_arm_handle_debug where we decide if this is a BP/WP set by guest
debugging or actually a real nested debug event which we currently fail
to deliver correctly.

If guest debug is not in effect then these BP/WP exceptions should be
delivered directly to the guest EL1 and never come to us.

I think these functions are TCG only for emulation of debug hardware.

>
> Signed-off-by: Samuel Ortiz <sameo@linux.intel.com>
> Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com>
> Reviewed-by: Robert Bradford <robert.bradford@intel.com>
> [PMD: Rebased]
> Signed-off-by: Philippe Mathieu-Daudé <philmd@redhat.com>
> ---
>  target/arm/helper.c    | 213 +++++++++++++++++++++++++++++++++++++++++
>  target/arm/internals.h |   6 ++
>  target/arm/op_helper.c | 213 -----------------------------------------
>  3 files changed, 219 insertions(+), 213 deletions(-)
>
> diff --git a/target/arm/helper.c b/target/arm/helper.c
> index 8c32b2bc0d..8b7ce0561b 100644
> --- a/target/arm/helper.c
> +++ b/target/arm/helper.c
> @@ -11508,3 +11508,216 @@ void arm_cpu_dump_state(CPUState *cs, FILE *f, int flags)
>          qemu_fprintf(f, "FPSCR: %08x\n", vfp_get_fpscr(env));
>      }
>  }
> +
> +/* Return true if the linked breakpoint entry lbn passes its checks */
> +static bool linked_bp_matches(ARMCPU *cpu, int lbn)
> +{
> +    CPUARMState *env = &cpu->env;
> +    uint64_t bcr = env->cp15.dbgbcr[lbn];
> +    int brps = extract32(cpu->dbgdidr, 24, 4);
> +    int ctx_cmps = 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<n>_EL1.LBN must indicate that breakpoint).
> +     * We choose the former.
> +     */
> +    if (lbn > brps || lbn < (brps - ctx_cmps)) {
> +        return false;
> +    }
> +
> +    bcr = env->cp15.dbgbcr[lbn];
> +
> +    if (extract64(bcr, 0, 1) == 0) {
> +        /* Linked breakpoint disabled : generate no events */
> +        return false;
> +    }
> +
> +    bt = 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 ASID),
> +     * since we don't implement the optional v7 context ID masking.
> +     */
> +    contextidr = 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 == 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;
> +}
> +
> +bool bp_wp_matches(ARMCPU *cpu, int n, bool is_wp)
> +{
> +    CPUARMState *env = &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 = arm_is_secure(env);
> +    int access_el = arm_current_el(env);
> +
> +    if (is_wp) {
> +        CPUWatchpoint *wp = env->cpu_watchpoint[n];
> +
> +        if (!wp || !(wp->flags & BP_WATCHPOINT_HIT)) {
> +            return false;
> +        }
> +        cr = env->cp15.dbgwcr[n];
> +        if (wp->hitattrs.user) {
> +            /*
> +             * The LDRT/STRT/LDT/STT "unprivileged access" instructions should
> +             * match watchpoints as if they were accesses done at EL0, even if
> +             * the CPU is at EL1 or higher.
> +             */
> +            access_el = 0;
> +        }
> +    } else {
> +        uint64_t pc = is_a64(env) ? env->pc : env->regs[15];
> +
> +        if (!env->cpu_breakpoint[n] || env->cpu_breakpoint[n]->pc != pc) {
> +            return false;
> +        }
> +        cr = 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 = extract64(cr, 1, 2);
> +    hmc = extract64(cr, 13, 1);
> +    ssc = 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) == 0) {
> +            return false;
> +        }
> +        break;
> +    case 0:
> +        if (extract32(pac, 1, 1) == 0) {
> +            return false;
> +        }
> +        break;
> +    default:
> +        g_assert_not_reached();
> +    }
> +
> +    wt = extract64(cr, 20, 1);
> +    lbn = extract64(cr, 16, 4);
> +
> +    if (wt && !linked_bp_matches(cpu, lbn)) {
> +        return false;
> +    }
> +
> +    return true;
> +}
> +
> +static bool check_watchpoints(ARMCPU *cpu)
> +{
> +    CPUARMState *env = &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) == 0
> +        || !arm_generate_debug_exceptions(env)) {
> +        return false;
> +    }
> +
> +    for (n = 0; n < ARRAY_SIZE(env->cpu_watchpoint); n++) {
> +        if (bp_wp_matches(cpu, n, true)) {
> +            return true;
> +        }
> +    }
> +    return false;
> +}
> +
> +bool arm_debug_check_watchpoint(CPUState *cs, CPUWatchpoint *wp)
> +{
> +    /*
> +     * Called by core code when a CPU watchpoint fires; need to check if this
> +     * is also an architectural watchpoint match.
> +     */
> +    ARMCPU *cpu = ARM_CPU(cs);
> +
> +    return check_watchpoints(cpu);
> +}
> +
> +vaddr arm_adjust_watchpoint_address(CPUState *cs, vaddr addr, int len)
> +{
> +    ARMCPU *cpu = ARM_CPU(cs);
> +    CPUARMState *env = &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 == 1) {
> +            addr ^= 3;
> +        } else if (len == 2) {
> +            addr ^= 2;
> +        }
> +    }
> +
> +    return addr;
> +}
> diff --git a/target/arm/internals.h b/target/arm/internals.h
> index 56281d8ece..fbbc701bb0 100644
> --- a/target/arm/internals.h
> +++ b/target/arm/internals.h
> @@ -1042,6 +1042,12 @@ bool pmsav8_mpu_lookup(CPUARMState *env, uint32_t address,
>                         int *prot, bool *is_subpage,
>                         ARMMMUFaultInfo *fi, uint32_t *mregion);
>
> +/*
> + * Returns true when the current CPU execution context matches
> + * the watchpoint or the breakpoint pointed at by n.
> + */
> +bool bp_wp_matches(ARMCPU *cpu, int n, bool is_wp);
> +
>  #ifdef TARGET_AARCH64
>  void aarch64_cpu_dump_state(CPUState *cs, FILE *f, int flags);
>  #else
> diff --git a/target/arm/op_helper.c b/target/arm/op_helper.c
> index 63bce32810..68740e1b30 100644
> --- a/target/arm/op_helper.c
> +++ b/target/arm/op_helper.c
> @@ -1018,185 +1018,6 @@ void HELPER(pre_smc)(CPUARMState *env, uint32_t syndrome)
>      }
>  }
>
> -/* Return true if the linked breakpoint entry lbn passes its checks */
> -static bool linked_bp_matches(ARMCPU *cpu, int lbn)
> -{
> -    CPUARMState *env = &cpu->env;
> -    uint64_t bcr = env->cp15.dbgbcr[lbn];
> -    int brps = extract32(cpu->dbgdidr, 24, 4);
> -    int ctx_cmps = 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<n>_EL1.LBN must indicate that breakpoint).
> -     * We choose the former.
> -     */
> -    if (lbn > brps || lbn < (brps - ctx_cmps)) {
> -        return false;
> -    }
> -
> -    bcr = env->cp15.dbgbcr[lbn];
> -
> -    if (extract64(bcr, 0, 1) == 0) {
> -        /* Linked breakpoint disabled : generate no events */
> -        return false;
> -    }
> -
> -    bt = 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 ASID),
> -     * since we don't implement the optional v7 context ID masking.
> -     */
> -    contextidr = 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 == 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 = &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 = arm_is_secure(env);
> -    int access_el = arm_current_el(env);
> -
> -    if (is_wp) {
> -        CPUWatchpoint *wp = env->cpu_watchpoint[n];
> -
> -        if (!wp || !(wp->flags & BP_WATCHPOINT_HIT)) {
> -            return false;
> -        }
> -        cr = env->cp15.dbgwcr[n];
> -        if (wp->hitattrs.user) {
> -            /*
> -             * The LDRT/STRT/LDT/STT "unprivileged access" instructions should
> -             * match watchpoints as if they were accesses done at EL0, even if
> -             * the CPU is at EL1 or higher.
> -             */
> -            access_el = 0;
> -        }
> -    } else {
> -        uint64_t pc = is_a64(env) ? env->pc : env->regs[15];
> -
> -        if (!env->cpu_breakpoint[n] || env->cpu_breakpoint[n]->pc != pc) {
> -            return false;
> -        }
> -        cr = 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 = extract64(cr, 1, 2);
> -    hmc = extract64(cr, 13, 1);
> -    ssc = 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) == 0) {
> -            return false;
> -        }
> -        break;
> -    case 0:
> -        if (extract32(pac, 1, 1) == 0) {
> -            return false;
> -        }
> -        break;
> -    default:
> -        g_assert_not_reached();
> -    }
> -
> -    wt = extract64(cr, 20, 1);
> -    lbn = extract64(cr, 16, 4);
> -
> -    if (wt && !linked_bp_matches(cpu, lbn)) {
> -        return false;
> -    }
> -
> -    return true;
> -}
> -
> -static bool check_watchpoints(ARMCPU *cpu)
> -{
> -    CPUARMState *env = &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) == 0
> -        || !arm_generate_debug_exceptions(env)) {
> -        return false;
> -    }
> -
> -    for (n = 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 = &cpu->env;
> @@ -1227,40 +1048,6 @@ void HELPER(check_breakpoints)(CPUARMState *env)
>      }
>  }
>
> -bool arm_debug_check_watchpoint(CPUState *cs, CPUWatchpoint *wp)
> -{
> -    /*
> -     * Called by core code when a CPU watchpoint fires; need to check if this
> -     * is also an architectural watchpoint match.
> -     */
> -    ARMCPU *cpu = ARM_CPU(cs);
> -
> -    return check_watchpoints(cpu);
> -}
> -
> -vaddr arm_adjust_watchpoint_address(CPUState *cs, vaddr addr, int len)
> -{
> -    ARMCPU *cpu = ARM_CPU(cs);
> -    CPUARMState *env = &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 == 1) {
> -            addr ^= 3;
> -        } else if (len == 2) {
> -            addr ^= 2;
> -        }
> -    }
> -
> -    return addr;
> -}
> -
>  void arm_debug_excp_handler(CPUState *cs)
>  {
>      /* Called by core code when a watchpoint or breakpoint fires;


--
Alex Bennée


^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [Qemu-devel] [Qemu-arm] [PATCH v2 21/23] target/arm: Do not build TCG objects when TCG is off
  2019-06-15 15:43 ` [Qemu-devel] [PATCH v2 21/23] target/arm: Do not build TCG objects when TCG is off Philippe Mathieu-Daudé
@ 2019-06-17 14:49   ` Alex Bennée
  0 siblings, 0 replies; 51+ messages in thread
From: Alex Bennée @ 2019-06-17 14:49 UTC (permalink / raw)
  To: qemu-arm
  Cc: Peter Maydell, Philippe Mathieu-Daudé,
	qemu-devel, Robert Bradford, Samuel Ortiz


Philippe Mathieu-Daudé <philmd@redhat.com> writes:

> From: Samuel Ortiz <sameo@linux.intel.com>
>
> 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 <sameo@linux.intel.com>
> Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com>
> Reviewed-by: Robert Bradford <robert.bradford@intel.com>
> [PMD: Rebased]
> Signed-off-by: Philippe Mathieu-Daudé <philmd@redhat.com>
> ---
>
> We can also use:
>
>   ifeq ($(CONFIG_TCG),y)
>   ...
>   endif
>
> But long single line with macros from rules.mak are way easier to
> rebase. Now that this series is stable, I could change to ifeq if
> required.

Given you spent that time re-ordering stuff to keep it together I think
ifeq for blocks would be better. Some commentary in the Makefile.objs so
people know where to put their new files would also help.

>
>  target/arm/Makefile.objs | 18 +++++++++---------
>  1 file changed, 9 insertions(+), 9 deletions(-)
>
> diff --git a/target/arm/Makefile.objs b/target/arm/Makefile.objs
> index 5f3f965cc6..b8aa9c032a 100644
> --- a/target/arm/Makefile.objs
> +++ b/target/arm/Makefile.objs
> @@ -3,7 +3,7 @@ obj-y += cpu.o helper.o gdbstub.o
>  obj-$(TARGET_AARCH64) += cpu64.o gdbstub64.o
>
>  obj-$(CONFIG_SOFTMMU) += machine.o arch_dump.o monitor.o arm-powerctl.o
> -obj-$(CONFIG_SOFTMMU) += psci.o
> +obj-$(call land,$(CONFIG_TCG),$(CONFIG_SOFTMMU)) += psci.o
>
>  obj-$(CONFIG_KVM) += kvm.o
>  obj-$(call land,$(CONFIG_KVM),$(call lnot,$(TARGET_AARCH64))) += kvm32.o
> @@ -31,12 +31,12 @@ 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
>
> -obj-y += translate.o op_helper.o
> -obj-y += crypto_helper.o
> -obj-y += iwmmxt_helper.o vec_helper.o
> -obj-y += neon_helper.o vfp_helper.o
> -obj-$(call lor,$(CONFIG_USER_ONLY),$(CONFIG_ARM_V7M)) += v7m_helper.o
> +obj-$(CONFIG_TCG) += translate.o op_helper.o
> +obj-$(CONFIG_TCG) += crypto_helper.o
> +obj-$(CONFIG_TCG) += iwmmxt_helper.o vec_helper.o
> +obj-$(CONFIG_TCG) += neon_helper.o vfp_helper.o
> +obj-$(call lor,$(CONFIG_USER_ONLY),$(call land,$(CONFIG_TCG),$(CONFIG_ARM_V7M))) += v7m_helper.o
>
> -obj-$(TARGET_AARCH64) += translate-a64.o helper-a64.o
> -obj-$(TARGET_AARCH64) += translate-sve.o sve_helper.o
> -obj-$(TARGET_AARCH64) += pauth_helper.o
> +obj-$(call land,$(CONFIG_TCG),$(TARGET_AARCH64)) += translate-a64.o helper-a64.o
> +obj-$(call land,$(CONFIG_TCG),$(TARGET_AARCH64)) += translate-sve.o sve_helper.o
> +obj-$(call land,$(CONFIG_TCG),$(TARGET_AARCH64)) += pauth_helper.o


--
Alex Bennée


^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [Qemu-devel] [PATCH v2 20/23] target/arm: Define TCG dependent functions when TCG is enabled
  2019-06-15 15:43 ` [Qemu-devel] [PATCH v2 20/23] target/arm: Define TCG dependent functions when TCG is enabled Philippe Mathieu-Daudé
@ 2019-06-17 14:50   ` Alex Bennée
  0 siblings, 0 replies; 51+ messages in thread
From: Alex Bennée @ 2019-06-17 14:50 UTC (permalink / raw)
  To: qemu-devel
  Cc: Peter Maydell, qemu-arm, Philippe Mathieu-Daudé,
	Samuel Ortiz, Robert Bradford


Philippe Mathieu-Daudé <philmd@redhat.com> writes:

> From: Samuel Ortiz <sameo@linux.intel.com>
>
> do_interrupt, do_unaligned_access, do_transaction_failed and debug_excp
> are only relevant in the TCG context, so we should not define them
> when TCG is disabled.
>
> Signed-off-by: Samuel Ortiz <sameo@linux.intel.com>
> Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com>
> Reviewed-by: Robert Bradford <robert.bradford@intel.com>
> [PMD: Rebased]
> Signed-off-by: Philippe Mathieu-Daudé <philmd@redhat.com>

Reviewed-by: Alex Bennée <alex.bennee@linaro.org>

> ---
>  target/arm/cpu.c | 8 +++++---
>  1 file changed, 5 insertions(+), 3 deletions(-)
>
> diff --git a/target/arm/cpu.c b/target/arm/cpu.c
> index 2335659a85..3ffea857c4 100644
> --- a/target/arm/cpu.c
> +++ b/target/arm/cpu.c
> @@ -1557,7 +1557,7 @@ static void arm_v7m_class_init(ObjectClass *oc, void *data)
>      CPUClass *cc = CPU_CLASS(oc);
>
>      acc->info = data;
> -#ifndef CONFIG_USER_ONLY
> +#if !defined(CONFIG_USER_ONLY) && defined(CONFIG_TCG)
>      cc->do_interrupt = arm_v7m_cpu_do_interrupt;
>  #endif
>
> @@ -2172,22 +2172,24 @@ static void arm_cpu_class_init(ObjectClass *oc, void *data)
>      cc->gdb_read_register = arm_cpu_gdb_read_register;
>      cc->gdb_write_register = arm_cpu_gdb_write_register;
>  #ifndef CONFIG_USER_ONLY
> +#ifdef CONFIG_TCG
>      cc->do_interrupt = arm_cpu_do_interrupt;
>      cc->do_unaligned_access = arm_cpu_do_unaligned_access;
>      cc->do_transaction_failed = arm_cpu_do_transaction_failed;
> +    cc->debug_excp_handler = arm_debug_excp_handler;
> +#endif /* CONFIG_TCG */
>      cc->get_phys_page_attrs_debug = arm_cpu_get_phys_page_attrs_debug;
>      cc->asidx_from_attrs = arm_asidx_from_attrs;
>      cc->vmsd = &vmstate_arm_cpu;
>      cc->virtio_is_big_endian = arm_cpu_virtio_is_big_endian;
>      cc->write_elf64_note = arm_cpu_write_elf64_note;
>      cc->write_elf32_note = arm_cpu_write_elf32_note;
> -#endif
> +#endif /* CONFIG_USER_ONLY */
>      cc->gdb_num_core_regs = 26;
>      cc->gdb_core_xml_file = "arm-core.xml";
>      cc->gdb_arch_name = arm_gdb_arch_name;
>      cc->gdb_get_dynamic_xml = arm_gdb_get_dynamic_xml;
>      cc->gdb_stop_before_watchpoint = true;
> -    cc->debug_excp_handler = arm_debug_excp_handler;
>      cc->debug_check_watchpoint = arm_debug_check_watchpoint;
>  #if !defined(CONFIG_USER_ONLY)
>      cc->adjust_watchpoint_address = arm_adjust_watchpoint_address;


--
Alex Bennée


^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [Qemu-devel] [Qemu-arm] [PATCH v2 18/23] target/arm: Move CPU state dumping routines to helper.c
  2019-06-17 14:41   ` [Qemu-devel] [Qemu-arm] " Alex Bennée
  2019-06-17 14:45     ` Philippe Mathieu-Daudé
@ 2019-06-17 14:52     ` Peter Maydell
  1 sibling, 0 replies; 51+ messages in thread
From: Peter Maydell @ 2019-06-17 14:52 UTC (permalink / raw)
  To: Alex Bennée
  Cc: qemu-arm, Philippe Mathieu-Daudé,
	QEMU Developers, Robert Bradford, Samuel Ortiz

On Mon, 17 Jun 2019 at 15:41, Alex Bennée <alex.bennee@linaro.org> wrote:
> Hmm so helper is a mix of non-TCG and TCG bits whereas helper-a64.c is
> basically just TCG helpers. It makes me wonder if we are breaking a
> convention here as helper.c is traditionally only TCG helpers.

The original convention was:
 * op_helper.c has functions which need access to things which
   TCG puts in specific registers and which are accessed from
   C via gcc "register variables" (most notably the CPU env pointer)
 * helper.c has functions which don't need access to the register
   variables (a mishmash of stuff, usually including interrupt/exception
   handling)
 * some targets further split out some parts of the C code into other
   foo-helper.c files
This distinction became entirely moot when we reworked the TCG code
to no longer use register variables (but instead pass in the env
pointer and so on directly as a function argument). You can still
see the comments at the top of target/i386/{op_helper,helper}.c that
claim this is what the files are for, though :-)

So these days there is really no fixed convention, except that
when we've added new things we've sometimes put them in their
own .c file. helper-a64.c in particular is on its own because it's
code that's only compiled into aarch64-softmmu, not arm-softmmu.

> It feels like there should be different file that is unambiguously used
> for both TCG and KVM based workloads where things like the cpu dump code
> can live.

Some sort of split like this seems like a good idea. I don't
know if any of the other target archs have already got a
good convention/naming scheme we could copy?

thanks
-- PMM


^ permalink raw reply	[flat|nested] 51+ messages in thread

end of thread, other threads:[~2019-06-17 16:08 UTC | newest]

Thread overview: 51+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-06-15 15:43 [Qemu-devel] [PATCH v2 00/23] Support disabling TCG on ARM Philippe Mathieu-Daudé
2019-06-15 15:43 ` [Qemu-devel] [PATCH v2 01/23] target/arm: Makefile cleanup (Aarch64) Philippe Mathieu-Daudé
2019-06-17 11:36   ` [Qemu-devel] [Qemu-arm] " Alex Bennée
2019-06-15 15:43 ` [Qemu-devel] [PATCH v2 02/23] target/arm: Makefile cleanup (ARM) Philippe Mathieu-Daudé
2019-06-17 11:36   ` [Qemu-devel] [Qemu-arm] " Alex Bennée
2019-06-17 11:37   ` Alex Bennée
2019-06-15 15:43 ` [Qemu-devel] [PATCH v2 03/23] target/arm: Makefile cleanup (KVM) Philippe Mathieu-Daudé
2019-06-17 11:37   ` [Qemu-devel] [Qemu-arm] " Alex Bennée
2019-06-15 15:43 ` [Qemu-devel] [PATCH v2 04/23] target/arm: Makefile cleanup (softmmu) Philippe Mathieu-Daudé
2019-06-17 11:38   ` [Qemu-devel] [Qemu-arm] " Alex Bennée
2019-06-15 15:43 ` [Qemu-devel] [PATCH v2 05/23] target/arm: Add copyright boilerplate Philippe Mathieu-Daudé
2019-06-17 11:39   ` [Qemu-devel] [Qemu-arm] " Alex Bennée
2019-06-15 15:43 ` [Qemu-devel] [PATCH v2 06/23] target/arm: Fix multiline comment syntax Philippe Mathieu-Daudé
2019-06-17 11:40   ` [Qemu-devel] [Qemu-arm] " Alex Bennée
2019-06-15 15:43 ` [Qemu-devel] [PATCH v2 07/23] target/arm: Declare some function publicly Philippe Mathieu-Daudé
2019-06-17 14:07   ` [Qemu-devel] [Qemu-arm] " Alex Bennée
2019-06-15 15:43 ` [Qemu-devel] [PATCH v2 08/23] target/arm: Move all v7m insn helpers into their own file Philippe Mathieu-Daudé
2019-06-17 11:42   ` Alex Bennée
2019-06-17 12:12     ` Philippe Mathieu-Daudé
2019-06-15 15:43 ` [Qemu-devel] [PATCH v2 09/23] target/arm: Move code around Philippe Mathieu-Daudé
2019-06-17 14:07   ` [Qemu-devel] [Qemu-arm] " Alex Bennée
2019-06-15 15:43 ` [Qemu-devel] [PATCH v2 10/23] target/arm: Move the v7-M Security State helpers to v7m_helper Philippe Mathieu-Daudé
2019-06-17 14:08   ` [Qemu-devel] [Qemu-arm] " Alex Bennée
2019-06-15 15:43 ` [Qemu-devel] [PATCH v2 11/23] target/arm: Declare v7m_cpacr_pass() publicly Philippe Mathieu-Daudé
2019-06-17 14:09   ` [Qemu-devel] [Qemu-arm] " Alex Bennée
2019-06-15 15:43 ` [Qemu-devel] [PATCH v2 12/23] target/arm: Move v7m exception handling routines to v7m_helper Philippe Mathieu-Daudé
2019-06-17 14:10   ` [Qemu-devel] [Qemu-arm] " Alex Bennée
2019-06-15 15:43 ` [Qemu-devel] [PATCH v2 13/23] target/arm: Make the v7-M Security State routines Philippe Mathieu-Daudé
2019-06-17 14:11   ` [Qemu-devel] [Qemu-arm] " Alex Bennée
2019-06-15 15:43 ` [Qemu-devel] [PATCH v2 14/23] target/arm: Move the DC ZVA helper into op_helper Philippe Mathieu-Daudé
2019-06-17 14:12   ` [Qemu-devel] [Qemu-arm] " Alex Bennée
2019-06-15 15:43 ` [Qemu-devel] [PATCH v2 15/23] target/arm: Make ARM TLB filling routine static Philippe Mathieu-Daudé
2019-06-17 14:16   ` [Qemu-devel] [Qemu-arm] " Alex Bennée
2019-06-15 15:43 ` [Qemu-devel] [PATCH v2 16/23] target/arm: Make arm_deliver_fault() static Philippe Mathieu-Daudé
2019-06-17 14:19   ` [Qemu-devel] [Qemu-arm] " Alex Bennée
2019-06-15 15:43 ` [Qemu-devel] [PATCH v2 17/23] target/arm: Fix coding style issues Philippe Mathieu-Daudé
2019-06-17 14:20   ` [Qemu-devel] [Qemu-arm] " Alex Bennée
2019-06-15 15:43 ` [Qemu-devel] [PATCH v2 18/23] target/arm: Move CPU state dumping routines to helper.c Philippe Mathieu-Daudé
2019-06-17 14:41   ` [Qemu-devel] [Qemu-arm] " Alex Bennée
2019-06-17 14:45     ` Philippe Mathieu-Daudé
2019-06-17 14:52     ` Peter Maydell
2019-06-15 15:43 ` [Qemu-devel] [PATCH v2 19/23] target/arm: Move watchpoints APIs " Philippe Mathieu-Daudé
2019-06-17 14:46   ` [Qemu-devel] [Qemu-arm] " Alex Bennée
2019-06-15 15:43 ` [Qemu-devel] [PATCH v2 20/23] target/arm: Define TCG dependent functions when TCG is enabled Philippe Mathieu-Daudé
2019-06-17 14:50   ` Alex Bennée
2019-06-15 15:43 ` [Qemu-devel] [PATCH v2 21/23] target/arm: Do not build TCG objects when TCG is off Philippe Mathieu-Daudé
2019-06-17 14:49   ` [Qemu-devel] [Qemu-arm] " Alex Bennée
2019-06-15 15:43 ` [Qemu-devel] [RFC PATCH v2 22/23] target/arm: Restrict semi-hosting to TCG Philippe Mathieu-Daudé
2019-06-17 14:07   ` Alex Bennée
2019-06-15 15:43 ` [Qemu-devel] [NOTFORMERGE PATCH v2 23/23] Missing symbols when building with --disable-tcg Philippe Mathieu-Daudé
2019-06-17 14:04   ` [Qemu-devel] [Qemu-arm] " Alex Bennée

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).