Changes since v7:
* Rebuild hflags for all successful nvic writes (Peter).
* Rebuild hflags for Xscale sctlr writes (Peter).
Changes since v6:
* Regen hflags in two more places for m-profile (patch 19).
Changes since v5:
* Fix the debug assertion ifdef in the final patch.
* Add more calls to arm_rebuild_hflags: CPSR and M-profile
These become two new patches, 18 & 19.
* Update some comments per review. (Alex)
Changes since v4:
* Split patch 1 into 15 smaller patches.
* Cache the new DEBUG_TARGET_EL field.
* Split out m-profile hflags separately from a-profile 32-bit.
* Move around non-cached tb flags as well, avoiding repetitive
checks for m-profile or other mutually exclusive conditions.
I haven't officially re-run the performance test quoted in the
last patch, but I have eyeballed "perf top", and have dug into
the compiled code a bit, which resulted in a few of the new
cleanup patches (e.g. cs_base, arm_mmu_idx_el, and
arm_cpu_data_is_big_endian).
...
r~
Richard Henderson (22):
target/arm: Split out rebuild_hflags_common
target/arm: Split out rebuild_hflags_a64
target/arm: Split out rebuild_hflags_common_32
target/arm: Split arm_cpu_data_is_big_endian
target/arm: Split out rebuild_hflags_m32
target/arm: Reduce tests vs M-profile in cpu_get_tb_cpu_state
target/arm: Split out rebuild_hflags_a32
target/arm: Split out rebuild_hflags_aprofile
target/arm: Hoist XSCALE_CPAR, VECLEN, VECSTRIDE in
cpu_get_tb_cpu_state
target/arm: Simplify set of PSTATE_SS in cpu_get_tb_cpu_state
target/arm: Hoist computation of TBFLAG_A32.VFPEN
target/arm: Add arm_rebuild_hflags
target/arm: Split out arm_mmu_idx_el
target/arm: Hoist store to cs_base in cpu_get_tb_cpu_state
target/arm: Add HELPER(rebuild_hflags_{a32,a64,m32})
target/arm: Rebuild hflags at EL changes
target/arm: Rebuild hflags at MSR writes
target/arm: Rebuild hflags at CPSR writes
target/arm: Rebuild hflags at Xscale SCTLR writes
target/arm: Rebuild hflags for M-profile
target/arm: Rebuild hflags for M-profile NVIC
target/arm: Rely on hflags correct in cpu_get_tb_cpu_state
target/arm/cpu.h | 84 +++++---
target/arm/helper.h | 4 +
target/arm/internals.h | 9 +
hw/intc/armv7m_nvic.c | 22 ++-
linux-user/syscall.c | 1 +
target/arm/cpu.c | 1 +
target/arm/helper-a64.c | 3 +
target/arm/helper.c | 393 ++++++++++++++++++++++++-------------
target/arm/m_helper.c | 6 +
target/arm/machine.c | 1 +
target/arm/op_helper.c | 4 +
target/arm/translate-a64.c | 13 +-
target/arm/translate.c | 33 +++-
13 files changed, 390 insertions(+), 184 deletions(-)
--
2.17.1
[PATCH v8 03/22] target/arm: Split out rebuild_hflags_common_32
Create a function to compute the values of the TBFLAG_A64 bits
that will be cached. For now, the env->hflags variable is not
used, and the results are fed back to cpu_get_tb_cpu_state.
Note that not all BTI related flags are cached, so we have to
test the BTI feature twice -- once for those bits moved out to
rebuild_hflags_a64 and once for those bits that remain in
cpu_get_tb_cpu_state.
Reviewed-by: Alex Bennée <alex.bennee@linaro.org>
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
target/arm/helper.c | 131 +++++++++++++++++++++++---------------------
1 file changed, 69 insertions(+), 62 deletions(-)
diff --git a/target/arm/helper.c b/target/arm/helper.c
index 8829d91ae1..69da04786e 100644
--- a/target/arm/helper.c+++ b/target/arm/helper.c
@@ -11070,6 +11070,71 @@ static uint32_t rebuild_hflags_common(CPUARMState *env, int fp_el,
return flags;
}
+static uint32_t rebuild_hflags_a64(CPUARMState *env, int el, int fp_el,+ ARMMMUIdx mmu_idx)+{+ ARMMMUIdx stage1 = stage_1_mmu_idx(mmu_idx);+ ARMVAParameters p0 = aa64_va_parameters_both(env, 0, stage1);+ uint32_t flags = 0;+ uint64_t sctlr;+ int tbii, tbid;++ flags = FIELD_DP32(flags, TBFLAG_ANY, AARCH64_STATE, 1);++ /* FIXME: ARMv8.1-VHE S2 translation regime. */+ if (regime_el(env, stage1) < 2) {+ ARMVAParameters p1 = aa64_va_parameters_both(env, -1, stage1);+ tbid = (p1.tbi << 1) | p0.tbi;+ tbii = tbid & ~((p1.tbid << 1) | p0.tbid);+ } else {+ tbid = p0.tbi;+ tbii = tbid & !p0.tbid;+ }++ flags = FIELD_DP32(flags, TBFLAG_A64, TBII, tbii);+ flags = FIELD_DP32(flags, TBFLAG_A64, TBID, tbid);++ if (cpu_isar_feature(aa64_sve, env_archcpu(env))) {+ int sve_el = sve_exception_el(env, el);+ uint32_t zcr_len;++ /*+ * If SVE is disabled, but FP is enabled,+ * then the effective len is 0.+ */+ if (sve_el != 0 && fp_el == 0) {+ zcr_len = 0;+ } else {+ zcr_len = sve_zcr_len_for_el(env, el);+ }+ flags = FIELD_DP32(flags, TBFLAG_A64, SVEEXC_EL, sve_el);+ flags = FIELD_DP32(flags, TBFLAG_A64, ZCR_LEN, zcr_len);+ }++ sctlr = arm_sctlr(env, el);++ if (cpu_isar_feature(aa64_pauth, env_archcpu(env))) {+ /*+ * In order to save space in flags, we record only whether+ * pauth is "inactive", meaning all insns are implemented as+ * a nop, or "active" when some action must be performed.+ * The decision of which action to take is left to a helper.+ */+ if (sctlr & (SCTLR_EnIA | SCTLR_EnIB | SCTLR_EnDA | SCTLR_EnDB)) {+ flags = FIELD_DP32(flags, TBFLAG_A64, PAUTH_ACTIVE, 1);+ }+ }++ if (cpu_isar_feature(aa64_bti, env_archcpu(env))) {+ /* Note that SCTLR_EL[23].BT == SCTLR_BT1. */+ if (sctlr & (el == 0 ? SCTLR_BT0 : SCTLR_BT1)) {+ flags = FIELD_DP32(flags, TBFLAG_A64, BT, 1);+ }+ }++ return rebuild_hflags_common(env, fp_el, mmu_idx, flags);+}+void cpu_get_tb_cpu_state(CPUARMState *env, target_ulong *pc,
target_ulong *cs_base, uint32_t *pflags)
{
@@ -11079,67 +11144,9 @@ void cpu_get_tb_cpu_state(CPUARMState *env, target_ulong *pc,
uint32_t flags = 0;
if (is_a64(env)) {
- ARMCPU *cpu = env_archcpu(env);- uint64_t sctlr;- *pc = env->pc;
- flags = FIELD_DP32(flags, TBFLAG_ANY, AARCH64_STATE, 1);-- /* Get control bits for tagged addresses. */- {- ARMMMUIdx stage1 = stage_1_mmu_idx(mmu_idx);- ARMVAParameters p0 = aa64_va_parameters_both(env, 0, stage1);- int tbii, tbid;-- /* FIXME: ARMv8.1-VHE S2 translation regime. */- if (regime_el(env, stage1) < 2) {- ARMVAParameters p1 = aa64_va_parameters_both(env, -1, stage1);- tbid = (p1.tbi << 1) | p0.tbi;- tbii = tbid & ~((p1.tbid << 1) | p0.tbid);- } else {- tbid = p0.tbi;- tbii = tbid & !p0.tbid;- }-- flags = FIELD_DP32(flags, TBFLAG_A64, TBII, tbii);- flags = FIELD_DP32(flags, TBFLAG_A64, TBID, tbid);- }-- if (cpu_isar_feature(aa64_sve, cpu)) {- int sve_el = sve_exception_el(env, current_el);- uint32_t zcr_len;-- /* If SVE is disabled, but FP is enabled,- * then the effective len is 0.- */- if (sve_el != 0 && fp_el == 0) {- zcr_len = 0;- } else {- zcr_len = sve_zcr_len_for_el(env, current_el);- }- flags = FIELD_DP32(flags, TBFLAG_A64, SVEEXC_EL, sve_el);- flags = FIELD_DP32(flags, TBFLAG_A64, ZCR_LEN, zcr_len);- }-- sctlr = arm_sctlr(env, current_el);-- if (cpu_isar_feature(aa64_pauth, cpu)) {- /*- * In order to save space in flags, we record only whether- * pauth is "inactive", meaning all insns are implemented as- * a nop, or "active" when some action must be performed.- * The decision of which action to take is left to a helper.- */- if (sctlr & (SCTLR_EnIA | SCTLR_EnIB | SCTLR_EnDA | SCTLR_EnDB)) {- flags = FIELD_DP32(flags, TBFLAG_A64, PAUTH_ACTIVE, 1);- }- }-- if (cpu_isar_feature(aa64_bti, cpu)) {- /* Note that SCTLR_EL[23].BT == SCTLR_BT1. */- if (sctlr & (current_el == 0 ? SCTLR_BT0 : SCTLR_BT1)) {- flags = FIELD_DP32(flags, TBFLAG_A64, BT, 1);- }+ flags = rebuild_hflags_a64(env, current_el, fp_el, mmu_idx);+ if (cpu_isar_feature(aa64_bti, env_archcpu(env))) { flags = FIELD_DP32(flags, TBFLAG_A64, BTYPE, env->btype);
}
} else {
@@ -11159,9 +11166,9 @@ void cpu_get_tb_cpu_state(CPUARMState *env, target_ulong *pc,
flags = FIELD_DP32(flags, TBFLAG_A32,
XSCALE_CPAR, env->cp15.c15_cpar);
}
- }- flags = rebuild_hflags_common(env, fp_el, mmu_idx, flags);+ flags = rebuild_hflags_common(env, fp_el, mmu_idx, flags);+ } /* The SS_ACTIVE and PSTATE_SS bits correspond to the state machine
* states defined in the ARM ARM for software singlestep:
--
2.17.1
[PATCH v8 01/22] target/arm: Split out rebuild_hflags_common
Create a function to compute the values of the TBFLAG_ANY bits
that will be cached. For now, the env->hflags variable is not
used, and the results are fed back to cpu_get_tb_cpu_state.
Reviewed-by: Alex Bennée <alex.bennee@linaro.org>
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
target/arm/cpu.h | 29 ++++++++++++++++++-----------target/arm/helper.c | 26 +++++++++++++++++++-------
2 files changed, 37 insertions(+), 18 deletions(-)
diff --git a/target/arm/cpu.h b/target/arm/cpu.h
index 297ad5e47a..ad79a6153b 100644
--- a/target/arm/cpu.h+++ b/target/arm/cpu.h
@@ -231,6 +231,9 @@ typedef struct CPUARMState {
uint32_t pstate;
uint32_t aarch64; /* 1 if CPU is in aarch64 state; inverse of PSTATE.nRW */
+ /* Cached TBFLAGS state. See below for which bits are included. */+ uint32_t hflags;+ /* Frequently accessed CPSR bits are stored separately for efficiency.
This contains all the other bits. Use cpsr_{read,write} to access
the whole CPSR. */
@@ -3140,15 +3143,18 @@ typedef ARMCPU ArchCPU;
#include "exec/cpu-all.h"
-/* Bit usage in the TB flags field: bit 31 indicates whether we are+/*+ * Bit usage in the TB flags field: bit 31 indicates whether we are * in 32 or 64 bit mode. The meaning of the other bits depends on that.
* We put flags which are shared between 32 and 64 bit mode at the top
* of the word, and flags which apply to only one mode at the bottom.
+ *+ * Unless otherwise noted, these bits are cached in env->hflags. */
FIELD(TBFLAG_ANY, AARCH64_STATE, 31, 1)
FIELD(TBFLAG_ANY, MMUIDX, 28, 3)
FIELD(TBFLAG_ANY, SS_ACTIVE, 27, 1)
-FIELD(TBFLAG_ANY, PSTATE_SS, 26, 1)+FIELD(TBFLAG_ANY, PSTATE_SS, 26, 1) /* Not cached. *//* Target EL if we take a floating-point-disabled exception */
FIELD(TBFLAG_ANY, FPEXC_EL, 24, 2)
FIELD(TBFLAG_ANY, BE_DATA, 23, 1)
@@ -3159,13 +3165,14 @@ FIELD(TBFLAG_ANY, BE_DATA, 23, 1)
FIELD(TBFLAG_ANY, DEBUG_TARGET_EL, 21, 2)
/* Bit usage when in AArch32 state: */
-FIELD(TBFLAG_A32, THUMB, 0, 1)-FIELD(TBFLAG_A32, VECLEN, 1, 3)-FIELD(TBFLAG_A32, VECSTRIDE, 4, 2)+FIELD(TBFLAG_A32, THUMB, 0, 1) /* Not cached. */+FIELD(TBFLAG_A32, VECLEN, 1, 3) /* Not cached. */+FIELD(TBFLAG_A32, VECSTRIDE, 4, 2) /* Not cached. *//*
* We store the bottom two bits of the CPAR as TB flags and handle
* checks on the other bits at runtime. This shares the same bits as
* VECSTRIDE, which is OK as no XScale CPU has VFP.
+ * Not cached, because VECLEN+VECSTRIDE are not cached. */
FIELD(TBFLAG_A32, XSCALE_CPAR, 4, 2)
/*
@@ -3174,15 +3181,15 @@ FIELD(TBFLAG_A32, XSCALE_CPAR, 4, 2)
* the same thing as the current security state of the processor!
*/
FIELD(TBFLAG_A32, NS, 6, 1)
-FIELD(TBFLAG_A32, VFPEN, 7, 1)-FIELD(TBFLAG_A32, CONDEXEC, 8, 8)+FIELD(TBFLAG_A32, VFPEN, 7, 1) /* Not cached. */+FIELD(TBFLAG_A32, CONDEXEC, 8, 8) /* Not cached. */FIELD(TBFLAG_A32, SCTLR_B, 16, 1)
/* For M profile only, set if FPCCR.LSPACT is set */
-FIELD(TBFLAG_A32, LSPACT, 18, 1)+FIELD(TBFLAG_A32, LSPACT, 18, 1) /* Not cached. *//* For M profile only, set if we must create a new FP context */
-FIELD(TBFLAG_A32, NEW_FP_CTXT_NEEDED, 19, 1)+FIELD(TBFLAG_A32, NEW_FP_CTXT_NEEDED, 19, 1) /* Not cached. *//* For M profile only, set if FPCCR.S does not match current security state */
-FIELD(TBFLAG_A32, FPCCR_S_WRONG, 20, 1)+FIELD(TBFLAG_A32, FPCCR_S_WRONG, 20, 1) /* Not cached. *//* For M profile only, Handler (ie not Thread) mode */
FIELD(TBFLAG_A32, HANDLER, 21, 1)
/* For M profile only, whether we should generate stack-limit checks */
@@ -3194,7 +3201,7 @@ FIELD(TBFLAG_A64, SVEEXC_EL, 2, 2)
FIELD(TBFLAG_A64, ZCR_LEN, 4, 4)
FIELD(TBFLAG_A64, PAUTH_ACTIVE, 8, 1)
FIELD(TBFLAG_A64, BT, 9, 1)
-FIELD(TBFLAG_A64, BTYPE, 10, 2)+FIELD(TBFLAG_A64, BTYPE, 10, 2) /* Not cached. */FIELD(TBFLAG_A64, TBID, 12, 2)
static inline bool bswap_code(bool sctlr_b)
diff --git a/target/arm/helper.c b/target/arm/helper.c
index 0d9a2d2ab7..8829d91ae1 100644
--- a/target/arm/helper.c+++ b/target/arm/helper.c
@@ -11054,6 +11054,22 @@ ARMMMUIdx arm_stage1_mmu_idx(CPUARMState *env)
}
#endif
+static uint32_t rebuild_hflags_common(CPUARMState *env, int fp_el,+ ARMMMUIdx mmu_idx, uint32_t flags)+{+ flags = FIELD_DP32(flags, TBFLAG_ANY, FPEXC_EL, fp_el);+ flags = FIELD_DP32(flags, TBFLAG_ANY, MMUIDX,+ arm_to_core_mmu_idx(mmu_idx));++ if (arm_cpu_data_is_big_endian(env)) {+ flags = FIELD_DP32(flags, TBFLAG_ANY, BE_DATA, 1);+ }+ if (arm_singlestep_active(env)) {+ flags = FIELD_DP32(flags, TBFLAG_ANY, SS_ACTIVE, 1);+ }+ return flags;+}+void cpu_get_tb_cpu_state(CPUARMState *env, target_ulong *pc,
target_ulong *cs_base, uint32_t *pflags)
{
@@ -11145,7 +11161,7 @@ void cpu_get_tb_cpu_state(CPUARMState *env, target_ulong *pc,
}
}
- flags = FIELD_DP32(flags, TBFLAG_ANY, MMUIDX, arm_to_core_mmu_idx(mmu_idx));+ flags = rebuild_hflags_common(env, fp_el, mmu_idx, flags); /* The SS_ACTIVE and PSTATE_SS bits correspond to the state machine
* states defined in the ARM ARM for software singlestep:
@@ -11153,9 +11169,9 @@ void cpu_get_tb_cpu_state(CPUARMState *env, target_ulong *pc,
* 0 x Inactive (the TB flag for SS is always 0)
* 1 0 Active-pending
* 1 1 Active-not-pending
+ * SS_ACTIVE is set in hflags; PSTATE_SS is computed every TB. */
- if (arm_singlestep_active(env)) {- flags = FIELD_DP32(flags, TBFLAG_ANY, SS_ACTIVE, 1);+ if (FIELD_EX32(flags, TBFLAG_ANY, SS_ACTIVE)) { if (is_a64(env)) {
if (env->pstate & PSTATE_SS) {
flags = FIELD_DP32(flags, TBFLAG_ANY, PSTATE_SS, 1);
@@ -11166,10 +11182,6 @@ void cpu_get_tb_cpu_state(CPUARMState *env, target_ulong *pc,
}
}
}
- if (arm_cpu_data_is_big_endian(env)) {- flags = FIELD_DP32(flags, TBFLAG_ANY, BE_DATA, 1);- }- flags = FIELD_DP32(flags, TBFLAG_ANY, FPEXC_EL, fp_el); if (arm_v7m_is_handler_mode(env)) {
flags = FIELD_DP32(flags, TBFLAG_A32, HANDLER, 1);
--
2.17.1
[PATCH v8 06/22] target/arm: Reduce tests vs M-profile in cpu_get_tb_cpu_state
Set TBFLAG_ANY.BE_DATA in rebuild_hflags_common_32 and
rebuild_hflags_a64 instead of rebuild_hflags_common, where we do
not need to re-test is_a64() nor re-compute the various inputs.
Reviewed-by: Alex Bennée <alex.bennee@linaro.org>
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
target/arm/cpu.h | 49 +++++++++++++++++++++++++++------------------target/arm/helper.c | 16 +++++++++++----
2 files changed, 42 insertions(+), 23 deletions(-)
diff --git a/target/arm/cpu.h b/target/arm/cpu.h
index ad79a6153b..4d961474ce 100644
--- a/target/arm/cpu.h+++ b/target/arm/cpu.h
@@ -3108,33 +3108,44 @@ static inline uint64_t arm_sctlr(CPUARMState *env, int el)
}
}
+static inline bool arm_cpu_data_is_big_endian_a32(CPUARMState *env,+ bool sctlr_b)+{+#ifdef CONFIG_USER_ONLY+ /*+ * In system mode, BE32 is modelled in line with the+ * architecture (as word-invariant big-endianness), where loads+ * and stores are done little endian but from addresses which+ * are adjusted by XORing with the appropriate constant. So the+ * endianness to use for the raw data access is not affected by+ * SCTLR.B.+ * In user mode, however, we model BE32 as byte-invariant+ * big-endianness (because user-only code cannot tell the+ * difference), and so we need to use a data access endianness+ * that depends on SCTLR.B.+ */+ if (sctlr_b) {+ return true;+ }+#endif+ /* In 32bit endianness is determined by looking at CPSR's E bit */+ return env->uncached_cpsr & CPSR_E;+}++static inline bool arm_cpu_data_is_big_endian_a64(int el, uint64_t sctlr)+{+ return sctlr & (el ? SCTLR_EE : SCTLR_E0E);+}/* Return true if the processor is in big-endian mode. */
static inline bool arm_cpu_data_is_big_endian(CPUARMState *env)
{
- /* In 32bit endianness is determined by looking at CPSR's E bit */ if (!is_a64(env)) {
- return-#ifdef CONFIG_USER_ONLY- /* In system mode, BE32 is modelled in line with the- * architecture (as word-invariant big-endianness), where loads- * and stores are done little endian but from addresses which- * are adjusted by XORing with the appropriate constant. So the- * endianness to use for the raw data access is not affected by- * SCTLR.B.- * In user mode, however, we model BE32 as byte-invariant- * big-endianness (because user-only code cannot tell the- * difference), and so we need to use a data access endianness- * that depends on SCTLR.B.- */- arm_sctlr_b(env) ||-#endif- ((env->uncached_cpsr & CPSR_E) ? 1 : 0);+ return arm_cpu_data_is_big_endian_a32(env, arm_sctlr_b(env)); } else {
int cur_el = arm_current_el(env);
uint64_t sctlr = arm_sctlr(env, cur_el);
-- return (sctlr & (cur_el ? SCTLR_EE : SCTLR_E0E)) != 0;+ return arm_cpu_data_is_big_endian_a64(cur_el, sctlr); }
}
diff --git a/target/arm/helper.c b/target/arm/helper.c
index f05d042474..4c65476d93 100644
--- a/target/arm/helper.c+++ b/target/arm/helper.c
@@ -11061,9 +11061,6 @@ static uint32_t rebuild_hflags_common(CPUARMState *env, int fp_el,
flags = FIELD_DP32(flags, TBFLAG_ANY, MMUIDX,
arm_to_core_mmu_idx(mmu_idx));
- if (arm_cpu_data_is_big_endian(env)) {- flags = FIELD_DP32(flags, TBFLAG_ANY, BE_DATA, 1);- } if (arm_singlestep_active(env)) {
flags = FIELD_DP32(flags, TBFLAG_ANY, SS_ACTIVE, 1);
}
@@ -11073,7 +11070,14 @@ static uint32_t rebuild_hflags_common(CPUARMState *env, int fp_el,
static uint32_t rebuild_hflags_common_32(CPUARMState *env, int fp_el,
ARMMMUIdx mmu_idx, uint32_t flags)
{
- flags = FIELD_DP32(flags, TBFLAG_A32, SCTLR_B, arm_sctlr_b(env));+ bool sctlr_b = arm_sctlr_b(env);++ if (sctlr_b) {+ flags = FIELD_DP32(flags, TBFLAG_A32, SCTLR_B, 1);+ }+ if (arm_cpu_data_is_big_endian_a32(env, sctlr_b)) {+ flags = FIELD_DP32(flags, TBFLAG_ANY, BE_DATA, 1);+ } flags = FIELD_DP32(flags, TBFLAG_A32, NS, !access_secure_reg(env));
return rebuild_hflags_common(env, fp_el, mmu_idx, flags);
@@ -11122,6 +11126,10 @@ static uint32_t rebuild_hflags_a64(CPUARMState *env, int el, int fp_el,
sctlr = arm_sctlr(env, el);
+ if (arm_cpu_data_is_big_endian_a64(el, sctlr)) {+ flags = FIELD_DP32(flags, TBFLAG_ANY, BE_DATA, 1);+ }+ if (cpu_isar_feature(aa64_pauth, env_archcpu(env))) {
/*
* In order to save space in flags, we record only whether
--
2.17.1
[PATCH v8 18/22] target/arm: Rebuild hflags at CPSR writes
Continue setting, but not relying upon, env->hflags.
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
target/arm/helper.c | 10 ++++++++++
1 file changed, 10 insertions(+)
diff --git a/target/arm/helper.c b/target/arm/helper.c
index aae7b62458..c55783e540 100644
--- a/target/arm/helper.c+++ b/target/arm/helper.c
@@ -4174,6 +4174,16 @@ static void sctlr_write(CPUARMState *env, const ARMCPRegInfo *ri,
/* ??? Lots of these bits are not implemented. */
/* This may enable/disable the MMU, so do a TLB flush. */
tlb_flush(CPU(cpu));
++ if (ri->type & ARM_CP_SUPPRESS_TB_END) {+ /*+ * Normally we would always end the TB on an SCTLR write; see the+ * comment in ARMCPRegInfo sctlr initialization below for why Xscale+ * is special. Setting ARM_CP_SUPPRESS_TB_END also stops the rebuild+ * of hflags from the translator, so do it here.+ */+ arm_rebuild_hflags(env);+ }}
static CPAccessResult fpexc32_access(CPUARMState *env, const ARMCPRegInfo *ri,
--
2.17.1
[PATCH v8 08/22] target/arm: Split out rebuild_hflags_aprofile
Continue setting, but not relying upon, env->hflags.
Reviewed-by: Alex Bennée <alex.bennee@linaro.org>
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
target/arm/translate-a64.c | 13 +++++++++++--target/arm/translate.c | 28 +++++++++++++++++++++++-----
2 files changed, 34 insertions(+), 7 deletions(-)
diff --git a/target/arm/translate-a64.c b/target/arm/translate-a64.c
index 2d6cd09634..d4bebbe629 100644
--- a/target/arm/translate-a64.c+++ b/target/arm/translate-a64.c
@@ -1789,8 +1789,17 @@ static void handle_sys(DisasContext *s, uint32_t insn, bool isread,
if ((tb_cflags(s->base.tb) & CF_USE_ICOUNT) && (ri->type & ARM_CP_IO)) {
/* I/O operations must end the TB here (whether read or write) */
s->base.is_jmp = DISAS_UPDATE;
- } else if (!isread && !(ri->type & ARM_CP_SUPPRESS_TB_END)) {- /* We default to ending the TB on a coprocessor register write,+ }+ if (!isread && !(ri->type & ARM_CP_SUPPRESS_TB_END)) {+ /*+ * A write to any coprocessor regiser that ends a TB+ * must rebuild the hflags for the next TB.+ */+ TCGv_i32 tcg_el = tcg_const_i32(s->current_el);+ gen_helper_rebuild_hflags_a64(cpu_env, tcg_el);+ tcg_temp_free_i32(tcg_el);+ /*+ * We default to ending the TB on a coprocessor register write, * but allow this to be suppressed by the register definition
* (usually only necessary to work around guest bugs).
*/
diff --git a/target/arm/translate.c b/target/arm/translate.c
index 698c594e8c..cb47cd9744 100644
--- a/target/arm/translate.c+++ b/target/arm/translate.c
@@ -6890,6 +6890,8 @@ static int disas_coproc_insn(DisasContext *s, uint32_t insn)
ri = get_arm_cp_reginfo(s->cp_regs,
ENCODE_CP_REG(cpnum, is64, s->ns, crn, crm, opc1, opc2));
if (ri) {
+ bool need_exit_tb;+ /* Check access permissions */
if (!cp_access_ok(s->current_el, ri, isread)) {
return 1;
@@ -7068,14 +7070,30 @@ static int disas_coproc_insn(DisasContext *s, uint32_t insn)
}
}
- if ((tb_cflags(s->base.tb) & CF_USE_ICOUNT) && (ri->type & ARM_CP_IO)) {- /* I/O operations must end the TB here (whether read or write) */- gen_lookup_tb(s);- } else if (!isread && !(ri->type & ARM_CP_SUPPRESS_TB_END)) {- /* We default to ending the TB on a coprocessor register write,+ /* I/O operations must end the TB here (whether read or write) */+ need_exit_tb = ((tb_cflags(s->base.tb) & CF_USE_ICOUNT) &&+ (ri->type & ARM_CP_IO));++ if (!isread && !(ri->type & ARM_CP_SUPPRESS_TB_END)) {+ /*+ * A write to any coprocessor regiser that ends a TB+ * must rebuild the hflags for the next TB.+ */+ TCGv_i32 tcg_el = tcg_const_i32(s->current_el);+ if (arm_dc_feature(s, ARM_FEATURE_M)) {+ gen_helper_rebuild_hflags_m32(cpu_env, tcg_el);+ } else {+ gen_helper_rebuild_hflags_a32(cpu_env, tcg_el);+ }+ tcg_temp_free_i32(tcg_el);+ /*+ * We default to ending the TB on a coprocessor register write, * but allow this to be suppressed by the register definition
* (usually only necessary to work around guest bugs).
*/
+ need_exit_tb = true;+ }+ if (need_exit_tb) { gen_lookup_tb(s);
}
--
2.17.1
[PATCH v8 10/22] target/arm: Simplify set of PSTATE_SS in cpu_get_tb_cpu_state