All of lore.kernel.org
 help / color / mirror / Atom feed
* [RFC PATCH 00/35] target/arm: fully model WFxT instructions for A-profile
@ 2026-03-20 13:05 Alex Bennée
  2026-03-20 13:05 ` [RFC PATCH 01/35] target/arm: migrate basic syndrome helpers to registerfields Alex Bennée
                   ` (34 more replies)
  0 siblings, 35 replies; 74+ messages in thread
From: Alex Bennée @ 2026-03-20 13:05 UTC (permalink / raw)
  To: qemu-devel
  Cc: Alexander Graf, Peter Maydell, qemu-arm, Pedro Barbuda,
	Mohamed Mediouni, Alex Bennée

This series fully models the behaviour of WFxT instructions. We
already had support for WFE for M-profile but we left off A-profile as
it has more potential sources of wake-ups. The main one is the event
stream which includes events from significant bits of the timer
ticking over.

The series starts with some refactoring of the syndrome register
helpers to use registerfields. We then expand the WFIT trap handling
to report the register used. We then implement the event stream events
for SEV, global monitor and the timer related ones before enabling WFE
for A-profile and then finally WFET.

Note on AI usage. As an experiment I previously posted a series with
the help of Gemini. This series however is a ground up
re-implementation which takes some different approaches on modelling
the event stream. In particular rather than running multiple timers we
use the same wxft timer and just compute if the timeout or timer event
will come first.

The only bits that remain from the Gemini experiment are the tests at
the end of the series. I've split up the patches and audited the
boot.S changes but I've still to go through the mini-GIC library and
the test case itself.

Alex.

Alex Bennée (35):
  target/arm: migrate basic syndrome helpers to registerfields
  target/arm: migrate system/cp trap syndromes to registerfields
  target/arm: migrate FP/SIMD trap syndromes to registerfields
  target/arm: migrate eret trap syndromes to registerfields
  target/arm: migrate SME trap syndromes to registerfields
  target/arm: migrate PAC trap syndromes to registerfields
  target/arm: migrate BTI trap syndromes to registerfields
  target/arm: migrate BXJ trap syndromes to registerfields
  target/arm: migrate Granule Protection traps to registerfields
  target/arm: migrate fault syndromes to registerfields
  target/arm: migrate debug syndromes to registerfields
  target/arm: migrate wfx syndromes to registerfields
  target/arm: migrate gcs syndromes to registerfields
  target/arm: migrate memory op syndromes to registerfields
  target/arm: migrate check_hcr_el2_trap to use syndrome helper
  target/arm: use syndrome helpers in arm_cpu_do_interrupt_aarch32_hyp
  target/arm: use syndrome helpers to set SAME_EL EC bit
  target/arm: make whpx use syndrome helpers for decode
  target/arm: make hvf use syndrome helpers for decode
  target/arm: use syndrome helpers in merge_syn_data_abort
  target/arm: use syndrome helpers to query VNCR bit
  target/arm: remove old syndrome defines
  target/arm: report register in WFIT syndromes
  target/arm: remove event_register check from arm_cpu_has_work
  target/arm: redefine event stream fields
  target/arm: add gt_calc_next_event_stream
  target/arm: wrap event_register in a union
  target/arm: ensure aarch64 DISAS_WFE will exit
  target/arm: implements SEV/SEVL for all modes
  target/arm: implement global monitor events
  target/arm: enable event stream on WFE instructions
  target/arm: implement WFET
  tests/tcg: split stage 1 between devices and RAM
  tests/tcg: create a mini-gic3 library
  tests/tcg: add basic test for aarch64 wf[ie][t] insns

 target/arm/cpu.h                          |  21 +-
 target/arm/internals.h                    |  12 +-
 target/arm/syndrome.h                     | 587 ++++++++++++++++++----
 target/arm/tcg/helper-defs.h              |   3 +-
 tests/tcg/aarch64/system/lib/gicv3.h      |  56 +++
 target/arm/tcg/a32.decode                 |   5 +-
 target/arm/tcg/a64.decode                 |   5 +-
 target/arm/tcg/t16.decode                 |   4 +-
 target/arm/tcg/t32.decode                 |   4 +-
 hw/intc/armv7m_nvic.c                     |   2 +-
 target/arm/cpu.c                          |  11 +-
 target/arm/helper.c                       |  97 +++-
 target/arm/hvf/hvf.c                      |  14 +-
 target/arm/machine.c                      |   4 +-
 target/arm/tcg/debug.c                    |   2 +-
 target/arm/tcg/m_helper.c                 |   4 +-
 target/arm/tcg/op_helper.c                | 122 ++++-
 target/arm/tcg/tlb_helper.c               |   6 +-
 target/arm/tcg/translate-a64.c            |  60 ++-
 target/arm/tcg/translate.c                |  19 +-
 target/arm/tcg/vfp_helper.c               |   5 +-
 target/arm/whpx/whpx-all.c                |  13 +-
 tests/tcg/aarch64/system/lib/gicv3.c      |  77 +++
 tests/tcg/aarch64/system/wfx.c            | 126 +++++
 tests/tcg/aarch64/Makefile.softmmu-target |  15 +-
 tests/tcg/aarch64/system/boot.S           |  55 +-
 26 files changed, 1116 insertions(+), 213 deletions(-)
 create mode 100644 tests/tcg/aarch64/system/lib/gicv3.h
 create mode 100644 tests/tcg/aarch64/system/lib/gicv3.c
 create mode 100644 tests/tcg/aarch64/system/wfx.c

-- 
2.47.3



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

* [RFC PATCH 01/35] target/arm: migrate basic syndrome helpers to registerfields
  2026-03-20 13:05 [RFC PATCH 00/35] target/arm: fully model WFxT instructions for A-profile Alex Bennée
@ 2026-03-20 13:05 ` Alex Bennée
  2026-04-01  5:36   ` Richard Henderson
  2026-03-20 13:05 ` [RFC PATCH 02/35] target/arm: migrate system/cp trap syndromes " Alex Bennée
                   ` (33 subsequent siblings)
  34 siblings, 1 reply; 74+ messages in thread
From: Alex Bennée @ 2026-03-20 13:05 UTC (permalink / raw)
  To: qemu-devel
  Cc: Alexander Graf, Peter Maydell, qemu-arm, Pedro Barbuda,
	Mohamed Mediouni, Alex Bennée

We have a registerfields interface which we can use for defining
fields alongside helpers to access them. Define the basic syndrome
layout and convert the helpers that take the imm16 data directly.

Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
---
 target/arm/syndrome.h | 75 ++++++++++++++++++++++++++++++++-----------
 1 file changed, 57 insertions(+), 18 deletions(-)

diff --git a/target/arm/syndrome.h b/target/arm/syndrome.h
index bff61f052cc..517fb2368bc 100644
--- a/target/arm/syndrome.h
+++ b/target/arm/syndrome.h
@@ -25,7 +25,7 @@
 #ifndef TARGET_ARM_SYNDROME_H
 #define TARGET_ARM_SYNDROME_H
 
-#include "qemu/bitops.h"
+#include "hw/core/registerfields.h"
 
 /* Valid Syndrome Register EC field values */
 enum arm_exception_class {
@@ -76,6 +76,11 @@ enum arm_exception_class {
     EC_AA64_BKPT              = 0x3c,
 };
 
+/* Generic syndrome encoding layout for HSR and lower 32 bits of ESR_EL2 */
+FIELD(SYNDROME, EC, 26, 6)
+FIELD(SYNDROME, IL, 25, 1)
+FIELD(SYNDROME, ISS, 0, 25)
+
 typedef enum {
     SME_ET_AccessTrap,
     SME_ET_Streaming,
@@ -113,12 +118,12 @@ typedef enum {
 
 static inline uint32_t syn_get_ec(uint32_t syn)
 {
-    return syn >> ARM_EL_EC_SHIFT;
+    return FIELD_EX32(syn, SYNDROME, EC);
 }
 
 static inline uint32_t syn_set_ec(uint32_t syn, uint32_t ec)
 {
-    return deposit32(syn, ARM_EL_EC_SHIFT, ARM_EL_EC_LENGTH, ec);
+    return FIELD_DP32(syn, SYNDROME, EC, ec);
 }
 
 /*
@@ -133,49 +138,74 @@ static inline uint32_t syn_set_ec(uint32_t syn, uint32_t ec)
  */
 static inline uint32_t syn_uncategorized(void)
 {
-    return (EC_UNCATEGORIZED << ARM_EL_EC_SHIFT) | ARM_EL_IL;
+    uint32_t res = syn_set_ec(0, EC_UNCATEGORIZED);
+    res = FIELD_DP32(res, SYNDROME, IL, 1);
+    return res;
 }
 
+FIELD(ISS_IMM16, IMM16, 0, 16)
+
 static inline uint32_t syn_aa64_svc(uint32_t imm16)
 {
-    return (EC_AA64_SVC << ARM_EL_EC_SHIFT) | ARM_EL_IL | (imm16 & 0xffff);
+    uint32_t res = syn_set_ec(0, EC_AA64_SVC);
+    res = FIELD_DP32(res, SYNDROME, IL, 1);
+    res = FIELD_DP32(res, ISS_IMM16, IMM16, imm16);
+    return res;
 }
 
 static inline uint32_t syn_aa64_hvc(uint32_t imm16)
 {
-    return (EC_AA64_HVC << ARM_EL_EC_SHIFT) | ARM_EL_IL | (imm16 & 0xffff);
+    uint32_t res = syn_set_ec(0, EC_AA64_HVC);
+    res = FIELD_DP32(res, SYNDROME, IL, 1);
+    res = FIELD_DP32(res, ISS_IMM16, IMM16, imm16);
+    return res;
 }
 
 static inline uint32_t syn_aa64_smc(uint32_t imm16)
 {
-    return (EC_AA64_SMC << ARM_EL_EC_SHIFT) | ARM_EL_IL | (imm16 & 0xffff);
+    uint32_t res = syn_set_ec(0, EC_AA64_SMC);
+    res = FIELD_DP32(res, SYNDROME, IL, 1);
+    res = FIELD_DP32(res, ISS_IMM16, IMM16, imm16);
+    return res;
 }
 
 static inline uint32_t syn_aa32_svc(uint32_t imm16, bool is_16bit)
 {
-    return (EC_AA32_SVC << ARM_EL_EC_SHIFT) | (imm16 & 0xffff)
-        | (is_16bit ? 0 : ARM_EL_IL);
+    uint32_t res = syn_set_ec(0, EC_AA32_SVC);
+    res = FIELD_DP32(res, SYNDROME, IL, is_16bit ? 0 : 1);
+    res = FIELD_DP32(res, ISS_IMM16, IMM16, imm16);
+    return res;
 }
 
 static inline uint32_t syn_aa32_hvc(uint32_t imm16)
 {
-    return (EC_AA32_HVC << ARM_EL_EC_SHIFT) | ARM_EL_IL | (imm16 & 0xffff);
+    uint32_t res = syn_set_ec(0, EC_AA32_HVC);
+    res = FIELD_DP32(res, SYNDROME, IL, 1);
+    res = FIELD_DP32(res, ISS_IMM16, IMM16, imm16);
+    return res;
 }
 
 static inline uint32_t syn_aa32_smc(void)
 {
-    return (EC_AA32_SMC << ARM_EL_EC_SHIFT) | ARM_EL_IL;
+    uint32_t res = syn_set_ec(0, EC_AA32_SMC);
+    res = FIELD_DP32(res, SYNDROME, IL, 1);
+    return res;
 }
 
 static inline uint32_t syn_aa64_bkpt(uint32_t imm16)
 {
-    return (EC_AA64_BKPT << ARM_EL_EC_SHIFT) | ARM_EL_IL | (imm16 & 0xffff);
+    uint32_t res = syn_set_ec(0, EC_AA64_BKPT);
+    res = FIELD_DP32(res, SYNDROME, IL, 1);
+    res = FIELD_DP32(res, ISS_IMM16, IMM16, imm16);
+    return res;
 }
 
 static inline uint32_t syn_aa32_bkpt(uint32_t imm16, bool is_16bit)
 {
-    return (EC_AA32_BKPT << ARM_EL_EC_SHIFT) | (imm16 & 0xffff)
-        | (is_16bit ? 0 : ARM_EL_IL);
+    uint32_t res = syn_set_ec(0, EC_AA32_BKPT);
+    res = FIELD_DP32(res, SYNDROME, IL, is_16bit ? 0 : 1);
+    res = FIELD_DP32(res, ISS_IMM16, IMM16, imm16);
+    return res;
 }
 
 static inline uint32_t syn_aa64_sysregtrap(int op0, int op1, int op2,
@@ -246,7 +276,9 @@ static inline uint32_t syn_simd_access_trap(int cv, int cond, bool is_16bit)
 
 static inline uint32_t syn_sve_access_trap(void)
 {
-    return (EC_SVEACCESSTRAP << ARM_EL_EC_SHIFT) | ARM_EL_IL;
+    uint32_t res = syn_set_ec(0, EC_SVEACCESSTRAP);
+    res = FIELD_DP32(res, SYNDROME, IL, 1);
+    return res;
 }
 
 /*
@@ -361,12 +393,16 @@ static inline uint32_t syn_wfx(int cv, int cond, int ti, bool is_16bit)
 
 static inline uint32_t syn_illegalstate(void)
 {
-    return (EC_ILLEGALSTATE << ARM_EL_EC_SHIFT) | ARM_EL_IL;
+    uint32_t res = syn_set_ec(0, EC_ILLEGALSTATE);
+    res = FIELD_DP32(res, SYNDROME, IL, 1);
+    return res;
 }
 
 static inline uint32_t syn_pcalignment(void)
 {
-    return (EC_PCALIGNMENT << ARM_EL_EC_SHIFT) | ARM_EL_IL;
+    uint32_t res = syn_set_ec(0, EC_PCALIGNMENT);
+    res = FIELD_DP32(res, SYNDROME, IL, 1);
+    return res;
 }
 
 static inline uint32_t syn_gcs_data_check(GCSInstructionType it, int rn)
@@ -388,7 +424,10 @@ static inline uint32_t syn_gcs_gcsstr(int ra, int rn)
 
 static inline uint32_t syn_serror(uint32_t extra)
 {
-    return (EC_SERROR << ARM_EL_EC_SHIFT) | ARM_EL_IL | extra;
+    uint32_t res = syn_set_ec(0, EC_SERROR);
+    res = FIELD_DP32(res, SYNDROME, IL, 1);
+    res = FIELD_DP32(res, SYNDROME, ISS, extra);
+    return res;
 }
 
 static inline uint32_t syn_mop(bool is_set, bool is_setg, int options,
-- 
2.47.3



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

* [RFC PATCH 02/35] target/arm: migrate system/cp trap syndromes to registerfields
  2026-03-20 13:05 [RFC PATCH 00/35] target/arm: fully model WFxT instructions for A-profile Alex Bennée
  2026-03-20 13:05 ` [RFC PATCH 01/35] target/arm: migrate basic syndrome helpers to registerfields Alex Bennée
@ 2026-03-20 13:05 ` Alex Bennée
  2026-04-01  5:39   ` Richard Henderson
  2026-03-20 13:05 ` [RFC PATCH 03/35] target/arm: migrate FP/SIMD " Alex Bennée
                   ` (32 subsequent siblings)
  34 siblings, 1 reply; 74+ messages in thread
From: Alex Bennée @ 2026-03-20 13:05 UTC (permalink / raw)
  To: qemu-devel
  Cc: Alexander Graf, Peter Maydell, qemu-arm, Pedro Barbuda,
	Mohamed Mediouni, Alex Bennée

Migrate syn_aa64_sysregtrap and co-processor register trap syndromes
to the registerfields API. The co-processor syndromes are split
between single and duel register moves.

Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
---
 target/arm/syndrome.h | 118 +++++++++++++++++++++++++++++++++++-------
 1 file changed, 99 insertions(+), 19 deletions(-)

diff --git a/target/arm/syndrome.h b/target/arm/syndrome.h
index 517fb2368bc..3d2660614c6 100644
--- a/target/arm/syndrome.h
+++ b/target/arm/syndrome.h
@@ -208,53 +208,133 @@ static inline uint32_t syn_aa32_bkpt(uint32_t imm16, bool is_16bit)
     return res;
 }
 
+/*
+ * ISS encoding for an exception from MSR, MRS, or System instruction
+ * in AArch64 state.
+ */
+FIELD(SYSREG_ISS, ISREAD, 0, 1) /* Direction, 1 is read */
+FIELD(SYSREG_ISS, CRM, 1, 4)
+FIELD(SYSREG_ISS, RT, 5, 5)
+FIELD(SYSREG_ISS, CRN, 10, 4)
+FIELD(SYSREG_ISS, OP1, 14, 3)
+FIELD(SYSREG_ISS, OP2, 17, 3)
+FIELD(SYSREG_ISS, OP0, 20, 2)
+
 static inline uint32_t syn_aa64_sysregtrap(int op0, int op1, int op2,
                                            int crn, int crm, int rt,
                                            int isread)
 {
-    return (EC_SYSTEMREGISTERTRAP << ARM_EL_EC_SHIFT) | ARM_EL_IL
-        | (op0 << 20) | (op2 << 17) | (op1 << 14) | (crn << 10) | (rt << 5)
-        | (crm << 1) | isread;
+    uint32_t res = syn_set_ec(0, EC_SYSTEMREGISTERTRAP);
+    res = FIELD_DP32(res, SYNDROME, IL, 1);
+
+    res = FIELD_DP32(res, SYSREG_ISS, OP0, op0);
+    res = FIELD_DP32(res, SYSREG_ISS, OP2, op2);
+    res = FIELD_DP32(res, SYSREG_ISS, OP1, op1);
+    res = FIELD_DP32(res, SYSREG_ISS, CRN, crn);
+    res = FIELD_DP32(res, SYSREG_ISS, RT, rt);
+    res = FIELD_DP32(res, SYSREG_ISS, CRM, crm);
+    res = FIELD_DP32(res, SYSREG_ISS, ISREAD, isread);
+
+    return res;
 }
 
+/*
+ * ISS encoding for an exception from an MCR or MRC access
+ * (move to/from co-processor)
+ */
+FIELD(COPROC_ISS, ISREAD, 0, 1)
+FIELD(COPROC_ISS, CRM, 1, 4)
+FIELD(COPROC_ISS, RT, 5, 5)
+FIELD(COPROC_ISS, CRN, 10, 4)
+FIELD(COPROC_ISS, OP1, 14, 3)
+FIELD(COPROC_ISS, OP2, 17, 3)
+FIELD(COPROC_ISS, COND, 20, 4)
+FIELD(COPROC_ISS, CV, 24, 1)
+
 static inline uint32_t syn_cp14_rt_trap(int cv, int cond, int opc1, int opc2,
                                         int crn, int crm, int rt, int isread,
                                         bool is_16bit)
 {
-    return (EC_CP14RTTRAP << ARM_EL_EC_SHIFT)
-        | (is_16bit ? 0 : ARM_EL_IL)
-        | (cv << 24) | (cond << 20) | (opc2 << 17) | (opc1 << 14)
-        | (crn << 10) | (rt << 5) | (crm << 1) | isread;
+    uint32_t res = syn_set_ec(0, EC_CP14RTTRAP);
+    res = FIELD_DP32(res, SYNDROME, IL, is_16bit ? 0 : 1);
+
+    res = FIELD_DP32(res, COPROC_ISS, CV, cv);
+    res = FIELD_DP32(res, COPROC_ISS, COND, cond);
+    res = FIELD_DP32(res, COPROC_ISS, OP2, opc2);
+    res = FIELD_DP32(res, COPROC_ISS, OP1, opc1);
+    res = FIELD_DP32(res, COPROC_ISS, CRN, crn);
+    res = FIELD_DP32(res, COPROC_ISS, RT, rt);
+    res = FIELD_DP32(res, COPROC_ISS, CRM, crm);
+    res = FIELD_DP32(res, COPROC_ISS, ISREAD, isread);
+
+    return res;
 }
 
 static inline uint32_t syn_cp15_rt_trap(int cv, int cond, int opc1, int opc2,
                                         int crn, int crm, int rt, int isread,
                                         bool is_16bit)
 {
-    return (EC_CP15RTTRAP << ARM_EL_EC_SHIFT)
-        | (is_16bit ? 0 : ARM_EL_IL)
-        | (cv << 24) | (cond << 20) | (opc2 << 17) | (opc1 << 14)
-        | (crn << 10) | (rt << 5) | (crm << 1) | isread;
+    uint32_t res = syn_set_ec(0, EC_CP15RTTRAP);
+    res = FIELD_DP32(res, SYNDROME, IL, is_16bit ? 0 : 1);
+
+    res = FIELD_DP32(res, COPROC_ISS, CV, cv);
+    res = FIELD_DP32(res, COPROC_ISS, COND, cond);
+    res = FIELD_DP32(res, COPROC_ISS, OP2, opc2);
+    res = FIELD_DP32(res, COPROC_ISS, OP1, opc1);
+    res = FIELD_DP32(res, COPROC_ISS, CRN, crn);
+    res = FIELD_DP32(res, COPROC_ISS, RT, rt);
+    res = FIELD_DP32(res, COPROC_ISS, CRM, crm);
+    res = FIELD_DP32(res, COPROC_ISS, ISREAD, isread);
+
+    return res;
 }
 
+/*
+ * ISS encoding for an exception from an MCRR or MRRC access
+ * (move to/from co-processor with 2 regs)
+ */
+FIELD(COPROC_R2_ISS, ISREAD, 0, 1)
+FIELD(COPROC_R2_ISS, CRM, 1, 4)
+FIELD(COPROC_R2_ISS, RT, 5, 5)
+FIELD(COPROC_R2_ISS, RT2, 10, 5)
+FIELD(COPROC_R2_ISS, OP1, 16, 4)
+FIELD(COPROC_R2_ISS, COND, 20, 4)
+FIELD(COPROC_R2_ISS, CV, 24, 1)
+
 static inline uint32_t syn_cp14_rrt_trap(int cv, int cond, int opc1, int crm,
                                          int rt, int rt2, int isread,
                                          bool is_16bit)
 {
-    return (EC_CP14RRTTRAP << ARM_EL_EC_SHIFT)
-        | (is_16bit ? 0 : ARM_EL_IL)
-        | (cv << 24) | (cond << 20) | (opc1 << 16)
-        | (rt2 << 10) | (rt << 5) | (crm << 1) | isread;
+    uint32_t res = syn_set_ec(0, EC_CP14RRTTRAP);
+    res = FIELD_DP32(res, SYNDROME, IL, is_16bit ? 0 : 1);
+
+    res = FIELD_DP32(res, COPROC_R2_ISS, CV, cv);
+    res = FIELD_DP32(res, COPROC_R2_ISS, COND, cond);
+    res = FIELD_DP32(res, COPROC_R2_ISS, OP1, opc1);
+    res = FIELD_DP32(res, COPROC_R2_ISS, RT2, rt2);
+    res = FIELD_DP32(res, COPROC_R2_ISS, RT, rt);
+    res = FIELD_DP32(res, COPROC_R2_ISS, CRM, crm);
+    res = FIELD_DP32(res, COPROC_R2_ISS, ISREAD, isread);
+
+    return res;
 }
 
 static inline uint32_t syn_cp15_rrt_trap(int cv, int cond, int opc1, int crm,
                                          int rt, int rt2, int isread,
                                          bool is_16bit)
 {
-    return (EC_CP15RRTTRAP << ARM_EL_EC_SHIFT)
-        | (is_16bit ? 0 : ARM_EL_IL)
-        | (cv << 24) | (cond << 20) | (opc1 << 16)
-        | (rt2 << 10) | (rt << 5) | (crm << 1) | isread;
+    uint32_t res = syn_set_ec(0, EC_CP15RRTTRAP);
+    res = FIELD_DP32(res, SYNDROME, IL, is_16bit ? 0 : 1);
+
+    res = FIELD_DP32(res, COPROC_R2_ISS, CV, cv);
+    res = FIELD_DP32(res, COPROC_R2_ISS, COND, cond);
+    res = FIELD_DP32(res, COPROC_R2_ISS, OP1, opc1);
+    res = FIELD_DP32(res, COPROC_R2_ISS, RT2, rt2);
+    res = FIELD_DP32(res, COPROC_R2_ISS, RT, rt);
+    res = FIELD_DP32(res, COPROC_R2_ISS, CRM, crm);
+    res = FIELD_DP32(res, COPROC_R2_ISS, ISREAD, isread);
+
+    return res;
 }
 
 static inline uint32_t syn_fp_access_trap(int cv, int cond, bool is_16bit,
-- 
2.47.3



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

* [RFC PATCH 03/35] target/arm: migrate FP/SIMD trap syndromes to registerfields
  2026-03-20 13:05 [RFC PATCH 00/35] target/arm: fully model WFxT instructions for A-profile Alex Bennée
  2026-03-20 13:05 ` [RFC PATCH 01/35] target/arm: migrate basic syndrome helpers to registerfields Alex Bennée
  2026-03-20 13:05 ` [RFC PATCH 02/35] target/arm: migrate system/cp trap syndromes " Alex Bennée
@ 2026-03-20 13:05 ` Alex Bennée
  2026-04-01  5:43   ` Richard Henderson
  2026-03-20 13:05 ` [RFC PATCH 04/35] target/arm: migrate eret " Alex Bennée
                   ` (31 subsequent siblings)
  34 siblings, 1 reply; 74+ messages in thread
From: Alex Bennée @ 2026-03-20 13:05 UTC (permalink / raw)
  To: qemu-devel
  Cc: Alexander Graf, Peter Maydell, qemu-arm, Pedro Barbuda,
	Mohamed Mediouni, Alex Bennée

The syn_simd_access trap was never used so remove it. We should only
see the COPROC encoding on v7 architectures.

Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
---
 target/arm/syndrome.h | 25 +++++++++++++++----------
 1 file changed, 15 insertions(+), 10 deletions(-)

diff --git a/target/arm/syndrome.h b/target/arm/syndrome.h
index 3d2660614c6..5b5a5cb182e 100644
--- a/target/arm/syndrome.h
+++ b/target/arm/syndrome.h
@@ -337,21 +337,26 @@ static inline uint32_t syn_cp15_rrt_trap(int cv, int cond, int opc1, int crm,
     return res;
 }
 
+/*
+ * ISS encoding for an exception from an access to a register of
+ * instruction resulting from the FPEN or TFP traps.
+ */
+FIELD(FP_ISS, COPROC, 0, 4) /* ARMv7 only */
+FIELD(FP_ISS, COND, 20, 4)
+FIELD(FP_ISS, CV, 24, 1)
+
 static inline uint32_t syn_fp_access_trap(int cv, int cond, bool is_16bit,
                                           int coproc)
 {
     /* AArch32 FP trap or any AArch64 FP/SIMD trap: TA == 0 */
-    return (EC_ADVSIMDFPACCESSTRAP << ARM_EL_EC_SHIFT)
-        | (is_16bit ? 0 : ARM_EL_IL)
-        | (cv << 24) | (cond << 20) | coproc;
-}
+    uint32_t res = syn_set_ec(0, EC_ADVSIMDFPACCESSTRAP);
+    res = FIELD_DP32(res, SYNDROME, IL, is_16bit ? 0 : 1);
 
-static inline uint32_t syn_simd_access_trap(int cv, int cond, bool is_16bit)
-{
-    /* AArch32 SIMD trap: TA == 1 coproc == 0 */
-    return (EC_ADVSIMDFPACCESSTRAP << ARM_EL_EC_SHIFT)
-        | (is_16bit ? 0 : ARM_EL_IL)
-        | (cv << 24) | (cond << 20) | (1 << 5);
+    res = FIELD_DP32(res, FP_ISS, CV, cv);
+    res = FIELD_DP32(res, FP_ISS, COND, cond);
+    res = FIELD_DP32(res, FP_ISS, COPROC, coproc);
+
+    return res;
 }
 
 static inline uint32_t syn_sve_access_trap(void)
-- 
2.47.3



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

* [RFC PATCH 04/35] target/arm: migrate eret trap syndromes to registerfields
  2026-03-20 13:05 [RFC PATCH 00/35] target/arm: fully model WFxT instructions for A-profile Alex Bennée
                   ` (2 preceding siblings ...)
  2026-03-20 13:05 ` [RFC PATCH 03/35] target/arm: migrate FP/SIMD " Alex Bennée
@ 2026-03-20 13:05 ` Alex Bennée
  2026-04-05 23:21   ` Richard Henderson
  2026-03-20 13:05 ` [RFC PATCH 05/35] target/arm: migrate SME " Alex Bennée
                   ` (30 subsequent siblings)
  34 siblings, 1 reply; 74+ messages in thread
From: Alex Bennée @ 2026-03-20 13:05 UTC (permalink / raw)
  To: qemu-devel
  Cc: Alexander Graf, Peter Maydell, qemu-arm, Pedro Barbuda,
	Mohamed Mediouni, Alex Bennée

For simplicity keep the OP as a two bit field rather than the two
interlinked fields in the docs (ERET/ERETA).

Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
---
 target/arm/syndrome.h | 11 ++++++++++-
 1 file changed, 10 insertions(+), 1 deletion(-)

diff --git a/target/arm/syndrome.h b/target/arm/syndrome.h
index 5b5a5cb182e..b145a52769f 100644
--- a/target/arm/syndrome.h
+++ b/target/arm/syndrome.h
@@ -367,12 +367,21 @@ static inline uint32_t syn_sve_access_trap(void)
 }
 
 /*
+ * ISS encoding for an exception from an ERET, ERETAA or ERETAB
+ * instructions.
+ *
  * eret_op is bits [1:0] of the ERET instruction, so:
  * 0 for ERET, 2 for ERETAA, 3 for ERETAB.
  */
+FIELD(ERET_ISS, OP, 0, 2)
+
 static inline uint32_t syn_erettrap(int eret_op)
 {
-    return (EC_ERETTRAP << ARM_EL_EC_SHIFT) | ARM_EL_IL | eret_op;
+    uint32_t res = syn_set_ec(0, EC_ERETTRAP);
+    res = FIELD_DP32(res, SYNDROME, IL, 1);
+    res = FIELD_DP32(res, ERET_ISS, OP, eret_op);
+
+    return res;
 }
 
 static inline uint32_t syn_smetrap(SMEExceptionType etype, bool is_16bit)
-- 
2.47.3



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

* [RFC PATCH 05/35] target/arm: migrate SME trap syndromes to registerfields
  2026-03-20 13:05 [RFC PATCH 00/35] target/arm: fully model WFxT instructions for A-profile Alex Bennée
                   ` (3 preceding siblings ...)
  2026-03-20 13:05 ` [RFC PATCH 04/35] target/arm: migrate eret " Alex Bennée
@ 2026-03-20 13:05 ` Alex Bennée
  2026-04-05 23:22   ` Richard Henderson
  2026-03-20 13:05 ` [RFC PATCH 06/35] target/arm: migrate PAC " Alex Bennée
                   ` (29 subsequent siblings)
  34 siblings, 1 reply; 74+ messages in thread
From: Alex Bennée @ 2026-03-20 13:05 UTC (permalink / raw)
  To: qemu-devel
  Cc: Alexander Graf, Peter Maydell, qemu-arm, Pedro Barbuda,
	Mohamed Mediouni, Alex Bennée

Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
---
 target/arm/syndrome.h | 12 ++++++++++--
 1 file changed, 10 insertions(+), 2 deletions(-)

diff --git a/target/arm/syndrome.h b/target/arm/syndrome.h
index b145a52769f..abec0a4908e 100644
--- a/target/arm/syndrome.h
+++ b/target/arm/syndrome.h
@@ -384,10 +384,18 @@ static inline uint32_t syn_erettrap(int eret_op)
     return res;
 }
 
+/*
+ * ISS encoding for an exception due to SME functionality
+ */
+FIELD(SME_ISS, SMTC, 0, 2)
+
 static inline uint32_t syn_smetrap(SMEExceptionType etype, bool is_16bit)
 {
-    return (EC_SMETRAP << ARM_EL_EC_SHIFT)
-        | (is_16bit ? 0 : ARM_EL_IL) | etype;
+    uint32_t res = syn_set_ec(0, EC_SMETRAP);
+    res = FIELD_DP32(res, SYNDROME, IL, is_16bit ? 0 : 1);
+    res = FIELD_DP32(res, SME_ISS, SMTC, etype);
+
+    return res;
 }
 
 static inline uint32_t syn_pacfail(bool data, int keynumber)
-- 
2.47.3



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

* [RFC PATCH 06/35] target/arm: migrate PAC trap syndromes to registerfields
  2026-03-20 13:05 [RFC PATCH 00/35] target/arm: fully model WFxT instructions for A-profile Alex Bennée
                   ` (4 preceding siblings ...)
  2026-03-20 13:05 ` [RFC PATCH 05/35] target/arm: migrate SME " Alex Bennée
@ 2026-03-20 13:05 ` Alex Bennée
  2026-04-05 23:23   ` Richard Henderson
  2026-03-20 13:05 ` [RFC PATCH 07/35] target/arm: migrate BTI " Alex Bennée
                   ` (28 subsequent siblings)
  34 siblings, 1 reply; 74+ messages in thread
From: Alex Bennée @ 2026-03-20 13:05 UTC (permalink / raw)
  To: qemu-devel
  Cc: Alexander Graf, Peter Maydell, qemu-arm, Pedro Barbuda,
	Mohamed Mediouni, Alex Bennée

syn_pactrap is fairly simple as the ISS is all RES0.

Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
---
 target/arm/syndrome.h | 23 ++++++++++++++++++++---
 1 file changed, 20 insertions(+), 3 deletions(-)

diff --git a/target/arm/syndrome.h b/target/arm/syndrome.h
index abec0a4908e..19c7659fb4f 100644
--- a/target/arm/syndrome.h
+++ b/target/arm/syndrome.h
@@ -398,15 +398,32 @@ static inline uint32_t syn_smetrap(SMEExceptionType etype, bool is_16bit)
     return res;
 }
 
+/*
+ * ISS encoding for a PAC Fail exceptions
+ */
+FIELD(PACFAIL_ISS, BnA, 0, 1) /* B key or A key */
+FIELD(PACFAIL_ISS, DnI, 1, 1) /* Data or Instruction */
+
 static inline uint32_t syn_pacfail(bool data, int keynumber)
 {
-    int error_code = (data << 1) | keynumber;
-    return (EC_PACFAIL << ARM_EL_EC_SHIFT) | ARM_EL_IL | error_code;
+    uint32_t res = syn_set_ec(0, EC_PACFAIL);
+    res = FIELD_DP32(res, SYNDROME, IL, 1);
+
+    res = FIELD_DP32(res, PACFAIL_ISS, DnI, data);
+    res = FIELD_DP32(res, PACFAIL_ISS, BnA, keynumber);
+
+    return res;
 }
 
+/*
+ * ISS encoding for an exception from a trapped Pointer
+ * Authentication instruction is RES0
+ */
 static inline uint32_t syn_pactrap(void)
 {
-    return (EC_PACTRAP << ARM_EL_EC_SHIFT) | ARM_EL_IL;
+    uint32_t res = syn_set_ec(0, EC_PACTRAP);
+    res = FIELD_DP32(res, SYNDROME, IL, 1);
+    return res;
 }
 
 static inline uint32_t syn_btitrap(int btype)
-- 
2.47.3



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

* [RFC PATCH 07/35] target/arm: migrate BTI trap syndromes to registerfields
  2026-03-20 13:05 [RFC PATCH 00/35] target/arm: fully model WFxT instructions for A-profile Alex Bennée
                   ` (5 preceding siblings ...)
  2026-03-20 13:05 ` [RFC PATCH 06/35] target/arm: migrate PAC " Alex Bennée
@ 2026-03-20 13:05 ` Alex Bennée
  2026-04-05 23:28   ` Richard Henderson
  2026-03-20 13:05 ` [RFC PATCH 08/35] target/arm: migrate BXJ " Alex Bennée
                   ` (27 subsequent siblings)
  34 siblings, 1 reply; 74+ messages in thread
From: Alex Bennée @ 2026-03-20 13:05 UTC (permalink / raw)
  To: qemu-devel
  Cc: Alexander Graf, Peter Maydell, qemu-arm, Pedro Barbuda,
	Mohamed Mediouni, Alex Bennée

Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
---
 target/arm/syndrome.h | 11 ++++++++++-
 1 file changed, 10 insertions(+), 1 deletion(-)

diff --git a/target/arm/syndrome.h b/target/arm/syndrome.h
index 19c7659fb4f..0520e51a686 100644
--- a/target/arm/syndrome.h
+++ b/target/arm/syndrome.h
@@ -426,9 +426,18 @@ static inline uint32_t syn_pactrap(void)
     return res;
 }
 
+/*
+ * ISS encoding for an exception from a Branch Target Identification
+ * instruction.
+ */
+FIELD(BTI_ISS, BTYPE, 0, 2)
+
 static inline uint32_t syn_btitrap(int btype)
 {
-    return (EC_BTITRAP << ARM_EL_EC_SHIFT) | ARM_EL_IL | btype;
+    uint32_t res = syn_set_ec(0, EC_BTITRAP);
+    res = FIELD_DP32(res, SYNDROME, IL, 1);
+    res = FIELD_DP32(res, BTI_ISS, BTYPE, btype);
+    return res;
 }
 
 static inline uint32_t syn_bxjtrap(int cv, int cond, int rm)
-- 
2.47.3



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

* [RFC PATCH 08/35] target/arm: migrate BXJ trap syndromes to registerfields
  2026-03-20 13:05 [RFC PATCH 00/35] target/arm: fully model WFxT instructions for A-profile Alex Bennée
                   ` (6 preceding siblings ...)
  2026-03-20 13:05 ` [RFC PATCH 07/35] target/arm: migrate BTI " Alex Bennée
@ 2026-03-20 13:05 ` Alex Bennée
  2026-04-05 23:29   ` Richard Henderson
  2026-03-20 13:05 ` [RFC PATCH 09/35] target/arm: migrate Granule Protection traps " Alex Bennée
                   ` (26 subsequent siblings)
  34 siblings, 1 reply; 74+ messages in thread
From: Alex Bennée @ 2026-03-20 13:05 UTC (permalink / raw)
  To: qemu-devel
  Cc: Alexander Graf, Peter Maydell, qemu-arm, Pedro Barbuda,
	Mohamed Mediouni, Alex Bennée

This is an Armv7 specific syndrome for chips with Jazelle
functionality.

Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
---
 target/arm/syndrome.h | 20 ++++++++++++++++++--
 1 file changed, 18 insertions(+), 2 deletions(-)

diff --git a/target/arm/syndrome.h b/target/arm/syndrome.h
index 0520e51a686..fb86e7bf6a8 100644
--- a/target/arm/syndrome.h
+++ b/target/arm/syndrome.h
@@ -440,10 +440,26 @@ static inline uint32_t syn_btitrap(int btype)
     return res;
 }
 
+/*
+ * ISS encoding for trapped BXJ execution
+ *
+ * This is an Armv7 encoding.
+ */
+FIELD(BXJ_ISS, RM, 0, 4)
+/* bits 4:19 are Reserved, UNK/SBZP */
+FIELD(BXJ_ISS, COND, 20, 4)
+FIELD(BXJ_ISS, CV, 24, 1)
+
 static inline uint32_t syn_bxjtrap(int cv, int cond, int rm)
 {
-    return (EC_BXJTRAP << ARM_EL_EC_SHIFT) | ARM_EL_IL |
-        (cv << 24) | (cond << 20) | rm;
+    uint32_t res = syn_set_ec(0, EC_BXJTRAP);
+    res = FIELD_DP32(res, SYNDROME, IL, 1);
+
+    res = FIELD_DP32(res, BXJ_ISS, CV, cv);
+    res = FIELD_DP32(res, BXJ_ISS, COND, cond);
+    res = FIELD_DP32(res, BXJ_ISS, RM, rm);
+
+    return res;
 }
 
 static inline uint32_t syn_gpc(int s2ptw, int ind, int gpcsc, int vncr,
-- 
2.47.3



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

* [RFC PATCH 09/35] target/arm: migrate Granule Protection traps to registerfields
  2026-03-20 13:05 [RFC PATCH 00/35] target/arm: fully model WFxT instructions for A-profile Alex Bennée
                   ` (7 preceding siblings ...)
  2026-03-20 13:05 ` [RFC PATCH 08/35] target/arm: migrate BXJ " Alex Bennée
@ 2026-03-20 13:05 ` Alex Bennée
  2026-04-05 23:30   ` Richard Henderson
  2026-03-20 13:05 ` [RFC PATCH 10/35] target/arm: migrate fault syndromes " Alex Bennée
                   ` (25 subsequent siblings)
  34 siblings, 1 reply; 74+ messages in thread
From: Alex Bennée @ 2026-03-20 13:05 UTC (permalink / raw)
  To: qemu-devel
  Cc: Alexander Graf, Peter Maydell, qemu-arm, Pedro Barbuda,
	Mohamed Mediouni, Alex Bennée

Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
---
 target/arm/syndrome.h | 30 +++++++++++++++++++++++++++---
 1 file changed, 27 insertions(+), 3 deletions(-)

diff --git a/target/arm/syndrome.h b/target/arm/syndrome.h
index fb86e7bf6a8..3fd82f5b565 100644
--- a/target/arm/syndrome.h
+++ b/target/arm/syndrome.h
@@ -462,12 +462,36 @@ static inline uint32_t syn_bxjtrap(int cv, int cond, int rm)
     return res;
 }
 
+/*
+ * ISS encoding for a Granule Protection Check exception
+ *
+ * These are only reported to EL3
+ */
+FIELD(GPC_ISS, xFSC, 0, 6)
+FIELD(GPC_ISS, WnR, 6, 1) /* Write not Read */
+FIELD(GPC_ISS, S1PTW, 7, 1)
+FIELD(GPC_ISS, CM, 8, 1)
+FIELD(GPC_ISS, VNCR, 13, 1)
+FIELD(GPC_ISS, GPCSC, 14, 6)
+FIELD(GPC_ISS, InD, 20, 1) /* Instruction not Data access */
+FIELD(GPC_ISS, S2PTW, 21, 1)
+
 static inline uint32_t syn_gpc(int s2ptw, int ind, int gpcsc, int vncr,
                                int cm, int s1ptw, int wnr, int fsc)
 {
-    return (EC_GPC << ARM_EL_EC_SHIFT) | ARM_EL_IL | (s2ptw << 21)
-        | (ind << 20) | (gpcsc << 14) | (vncr << 13) | (cm << 8)
-        | (s1ptw << 7) | (wnr << 6) | fsc;
+    uint32_t res = syn_set_ec(0, EC_GPC);
+    res = FIELD_DP32(res, SYNDROME, IL, 1);
+
+    res = FIELD_DP32(res, GPC_ISS, S2PTW, s2ptw);
+    res = FIELD_DP32(res, GPC_ISS, InD, ind);
+    res = FIELD_DP32(res, GPC_ISS, GPCSC, gpcsc);
+    res = FIELD_DP32(res, GPC_ISS, VNCR, vncr);
+    res = FIELD_DP32(res, GPC_ISS, CM, cm);
+    res = FIELD_DP32(res, GPC_ISS, S1PTW, s1ptw);
+    res = FIELD_DP32(res, GPC_ISS, WnR, wnr);
+    res = FIELD_DP32(res, GPC_ISS, xFSC, fsc);
+
+    return res;
 }
 
 static inline uint32_t syn_insn_abort(int same_el, int ea, int s1ptw, int fsc)
-- 
2.47.3



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

* [RFC PATCH 10/35] target/arm: migrate fault syndromes to registerfields
  2026-03-20 13:05 [RFC PATCH 00/35] target/arm: fully model WFxT instructions for A-profile Alex Bennée
                   ` (8 preceding siblings ...)
  2026-03-20 13:05 ` [RFC PATCH 09/35] target/arm: migrate Granule Protection traps " Alex Bennée
@ 2026-03-20 13:05 ` Alex Bennée
  2026-04-05 23:32   ` Richard Henderson
  2026-03-20 13:05 ` [RFC PATCH 11/35] target/arm: migrate debug " Alex Bennée
                   ` (24 subsequent siblings)
  34 siblings, 1 reply; 74+ messages in thread
From: Alex Bennée @ 2026-03-20 13:05 UTC (permalink / raw)
  To: qemu-devel
  Cc: Alexander Graf, Peter Maydell, qemu-arm, Pedro Barbuda,
	Mohamed Mediouni, Alex Bennée

Migrate syn_insn_abort and syn_data_abort_* to the registerfields API.

Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
---
 target/arm/syndrome.h | 87 ++++++++++++++++++++++++++++++++++++-------
 1 file changed, 74 insertions(+), 13 deletions(-)

diff --git a/target/arm/syndrome.h b/target/arm/syndrome.h
index 3fd82f5b565..db92a8020e3 100644
--- a/target/arm/syndrome.h
+++ b/target/arm/syndrome.h
@@ -494,20 +494,64 @@ static inline uint32_t syn_gpc(int s2ptw, int ind, int gpcsc, int vncr,
     return res;
 }
 
+/*
+ * ISS encoding for an exception from an Instruction Abort
+ *
+ * (aka instruction abort)
+ */
+FIELD(IABORT_ISS, IFSC, 0, 6)
+FIELD(IABORT_ISS, S1PTW, 7, 1)
+FIELD(IABORT_ISS, EA, 9, 1)
+FIELD(IABORT_ISS, FnV, 10, 1) /* FAR not Valid */
+FIELD(IABORT_ISS, SET, 11, 2)
+FIELD(IABORT_ISS, PFV, 14, 1)
+FIELD(IABORT_ISS, TopLevel, 21, 1) /* FEAT_THE */
+
 static inline uint32_t syn_insn_abort(int same_el, int ea, int s1ptw, int fsc)
 {
-    return (EC_INSNABORT << ARM_EL_EC_SHIFT) | (same_el << ARM_EL_EC_SHIFT)
-        | ARM_EL_IL | (ea << 9) | (s1ptw << 7) | fsc;
+    uint32_t res = syn_set_ec(0, EC_INSNABORT + same_el);
+    res = FIELD_DP32(res, SYNDROME, IL, 1);
+
+    res = FIELD_DP32(res, IABORT_ISS, EA, ea);
+    res = FIELD_DP32(res, IABORT_ISS, S1PTW, s1ptw);
+    res = FIELD_DP32(res, IABORT_ISS, IFSC, fsc);
+
+    return res;
 }
 
+/*
+ * ISS encoding for an exception from a Data Abort
+ */
+FIELD(DABORT_ISS, DFSC, 0, 6)
+FIELD(DABORT_ISS, WNR, 6, 1)
+FIELD(DABORT_ISS, S1PTW, 7, 1)
+FIELD(DABORT_ISS, CM, 8, 1)
+FIELD(DABORT_ISS, EA, 9, 1)
+FIELD(DABORT_ISS, FnV, 10, 1)
+FIELD(DABORT_ISS, LST, 11, 2)
+FIELD(DABORT_ISS, VNCR, 13, 1)
+FIELD(DABORT_ISS, AR, 14, 1)
+FIELD(DABORT_ISS, SF, 15, 1)
+FIELD(DABORT_ISS, SRT, 16, 5)
+FIELD(DABORT_ISS, SSE, 21, 1)
+FIELD(DABORT_ISS, SAS, 22, 2)
+FIELD(DABORT_ISS, ISV, 24, 1)
+
 static inline uint32_t syn_data_abort_no_iss(int same_el, int fnv,
                                              int ea, int cm, int s1ptw,
                                              int wnr, int fsc)
 {
-    return (EC_DATAABORT << ARM_EL_EC_SHIFT) | (same_el << ARM_EL_EC_SHIFT)
-           | ARM_EL_IL
-           | (fnv << 10) | (ea << 9) | (cm << 8) | (s1ptw << 7)
-           | (wnr << 6) | fsc;
+    uint32_t res = syn_set_ec(0, EC_DATAABORT + same_el);
+    res = FIELD_DP32(res, SYNDROME, IL, 1);
+
+    res = FIELD_DP32(res, DABORT_ISS, FnV, fnv);
+    res = FIELD_DP32(res, DABORT_ISS, EA, ea);
+    res = FIELD_DP32(res, DABORT_ISS, CM, cm);
+    res = FIELD_DP32(res, DABORT_ISS, S1PTW, s1ptw);
+    res = FIELD_DP32(res, DABORT_ISS, WNR, wnr);
+    res = FIELD_DP32(res, DABORT_ISS, DFSC, fsc);
+
+    return res;
 }
 
 static inline uint32_t syn_data_abort_with_iss(int same_el,
@@ -517,11 +561,22 @@ static inline uint32_t syn_data_abort_with_iss(int same_el,
                                                int wnr, int fsc,
                                                bool is_16bit)
 {
-    return (EC_DATAABORT << ARM_EL_EC_SHIFT) | (same_el << ARM_EL_EC_SHIFT)
-           | (is_16bit ? 0 : ARM_EL_IL)
-           | ARM_EL_ISV | (sas << 22) | (sse << 21) | (srt << 16)
-           | (sf << 15) | (ar << 14)
-           | (ea << 9) | (cm << 8) | (s1ptw << 7) | (wnr << 6) | fsc;
+    uint32_t res = syn_set_ec(0, EC_DATAABORT + same_el);
+    res = FIELD_DP32(res, SYNDROME, IL, is_16bit ? 0 : 1);
+
+    res = FIELD_DP32(res, DABORT_ISS, ISV, 1);
+    res = FIELD_DP32(res, DABORT_ISS, SAS, sas);
+    res = FIELD_DP32(res, DABORT_ISS, SSE, sse);
+    res = FIELD_DP32(res, DABORT_ISS, SRT, srt);
+    res = FIELD_DP32(res, DABORT_ISS, SF, sf);
+    res = FIELD_DP32(res, DABORT_ISS, AR, ar);
+    res = FIELD_DP32(res, DABORT_ISS, EA, ea);
+    res = FIELD_DP32(res, DABORT_ISS, CM, cm);
+    res = FIELD_DP32(res, DABORT_ISS, S1PTW, s1ptw);
+    res = FIELD_DP32(res, DABORT_ISS, WNR, wnr);
+    res = FIELD_DP32(res, DABORT_ISS, DFSC, fsc);
+
+    return res;
 }
 
 /*
@@ -530,8 +585,14 @@ static inline uint32_t syn_data_abort_with_iss(int same_el,
  */
 static inline uint32_t syn_data_abort_vncr(int ea, int wnr, int fsc)
 {
-    return (EC_DATAABORT << ARM_EL_EC_SHIFT) | (1 << ARM_EL_EC_SHIFT)
-        | ARM_EL_IL | ARM_EL_VNCR | (wnr << 6) | fsc;
+    uint32_t res = syn_set_ec(0, EC_DATAABORT_SAME_EL);
+    res = FIELD_DP32(res, SYNDROME, IL, 1);
+
+    res = FIELD_DP32(res, DABORT_ISS, VNCR, 1);
+    res = FIELD_DP32(res, DABORT_ISS, WNR, wnr);
+    res = FIELD_DP32(res, DABORT_ISS, DFSC, fsc);
+
+    return res;
 }
 
 static inline uint32_t syn_swstep(int same_el, int isv, int ex)
-- 
2.47.3



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

* [RFC PATCH 11/35] target/arm: migrate debug syndromes to registerfields
  2026-03-20 13:05 [RFC PATCH 00/35] target/arm: fully model WFxT instructions for A-profile Alex Bennée
                   ` (9 preceding siblings ...)
  2026-03-20 13:05 ` [RFC PATCH 10/35] target/arm: migrate fault syndromes " Alex Bennée
@ 2026-03-20 13:05 ` Alex Bennée
  2026-04-05 23:37   ` Richard Henderson
  2026-03-20 13:05 ` [RFC PATCH 12/35] target/arm: migrate wfx " Alex Bennée
                   ` (23 subsequent siblings)
  34 siblings, 1 reply; 74+ messages in thread
From: Alex Bennée @ 2026-03-20 13:05 UTC (permalink / raw)
  To: qemu-devel
  Cc: Alexander Graf, Peter Maydell, qemu-arm, Pedro Barbuda,
	Mohamed Mediouni, Alex Bennée

Migrate syn_swstep, syn_watchpoint and syn_breakpoint to the
registerfields API.

Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
---
 target/arm/syndrome.h | 54 ++++++++++++++++++++++++++++++++++++++-----
 1 file changed, 48 insertions(+), 6 deletions(-)

diff --git a/target/arm/syndrome.h b/target/arm/syndrome.h
index db92a8020e3..3bd98a30367 100644
--- a/target/arm/syndrome.h
+++ b/target/arm/syndrome.h
@@ -595,22 +595,64 @@ static inline uint32_t syn_data_abort_vncr(int ea, int wnr, int fsc)
     return res;
 }
 
+/*
+ * ISS encoding for an exception from a Software Step exception.
+ */
+FIELD(SOFTSTEP_ISS, IFSC, 0, 6)
+FIELD(SOFTSTEP_ISS, EX, 6, 1)
+FIELD(SOFTSTEP_ISS, ISV, 24, 1)
+
 static inline uint32_t syn_swstep(int same_el, int isv, int ex)
 {
-    return (EC_SOFTWARESTEP << ARM_EL_EC_SHIFT) | (same_el << ARM_EL_EC_SHIFT)
-        | ARM_EL_IL | (isv << 24) | (ex << 6) | 0x22;
+    uint32_t res = syn_set_ec(0, EC_SOFTWARESTEP + same_el);
+    res = FIELD_DP32(res, SYNDROME, IL, 1);
+
+    res = FIELD_DP32(res, SOFTSTEP_ISS, ISV, isv);
+    res = FIELD_DP32(res, SOFTSTEP_ISS, EX, ex);
+    res = FIELD_DP32(res, SOFTSTEP_ISS, IFSC, 0x22);
+
+    return res;
 }
 
+/*
+ * ISS encoding for an exception from a Watchpoint exception
+ */
+FIELD(WATCHPOINT_ISS, DFSC, 0, 6)
+FIELD(WATCHPOINT_ISS, WNR, 6, 1)
+FIELD(WATCHPOINT_ISS, CM, 8, 1)
+FIELD(WATCHPOINT_ISS, FnV, 10, 1)
+FIELD(WATCHPOINT_ISS, VNCR, 13, 1) /* FEAT_NV2 */
+FIELD(WATCHPOINT_ISS, FnP, 15, 1)
+FIELD(WATCHPOINT_ISS, WPF, 16, 1)
+/* bellow mandatory from FEAT_Debugv8p9 */
+FIELD(WATCHPOINT_ISS, WPTV, 17, 1) /* FEAT_Debugv8p2 - WPT valid */
+FIELD(WATCHPOINT_ISS, WPT, 18, 6) /* FEAT_Debugv8p2 - missing WP number */
+
 static inline uint32_t syn_watchpoint(int same_el, int cm, int wnr)
 {
-    return (EC_WATCHPOINT << ARM_EL_EC_SHIFT) | (same_el << ARM_EL_EC_SHIFT)
-        | ARM_EL_IL | (cm << 8) | (wnr << 6) | 0x22;
+    uint32_t res = syn_set_ec(0, EC_WATCHPOINT + same_el);
+    res = FIELD_DP32(res, SYNDROME, IL, 1);
+
+    res = FIELD_DP32(res, WATCHPOINT_ISS, CM, cm);
+    res = FIELD_DP32(res, WATCHPOINT_ISS, WNR, wnr);
+    res = FIELD_DP32(res, WATCHPOINT_ISS, DFSC, 0x22);
+
+    return res;
 }
 
+/*
+ * ISS encoding for an exception from a Breakpoint or a Vector Catch
+ * debug exception.
+ */
+FIELD(BREAKPOINT_ISS, IFSC, 0, 6)
+
 static inline uint32_t syn_breakpoint(int same_el)
 {
-    return (EC_BREAKPOINT << ARM_EL_EC_SHIFT) | (same_el << ARM_EL_EC_SHIFT)
-        | ARM_EL_IL | 0x22;
+    uint32_t res = syn_set_ec(0, EC_BREAKPOINT + same_el);
+    res = FIELD_DP32(res, SYNDROME, IL, 1);
+    res = FIELD_DP32(res, BREAKPOINT_ISS, IFSC, 0x22);
+
+    return res;
 }
 
 static inline uint32_t syn_wfx(int cv, int cond, int ti, bool is_16bit)
-- 
2.47.3



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

* [RFC PATCH 12/35] target/arm: migrate wfx syndromes to registerfields
  2026-03-20 13:05 [RFC PATCH 00/35] target/arm: fully model WFxT instructions for A-profile Alex Bennée
                   ` (10 preceding siblings ...)
  2026-03-20 13:05 ` [RFC PATCH 11/35] target/arm: migrate debug " Alex Bennée
@ 2026-03-20 13:05 ` Alex Bennée
  2026-04-05 23:41   ` Richard Henderson
  2026-03-20 13:05 ` [RFC PATCH 13/35] target/arm: migrate gcs " Alex Bennée
                   ` (22 subsequent siblings)
  34 siblings, 1 reply; 74+ messages in thread
From: Alex Bennée @ 2026-03-20 13:05 UTC (permalink / raw)
  To: qemu-devel
  Cc: Alexander Graf, Peter Maydell, qemu-arm, Pedro Barbuda,
	Mohamed Mediouni, Alex Bennée

This will help later when we expand the fields we report.

Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
---
 target/arm/syndrome.h | 20 +++++++++++++++++---
 1 file changed, 17 insertions(+), 3 deletions(-)

diff --git a/target/arm/syndrome.h b/target/arm/syndrome.h
index 3bd98a30367..503b19b5d02 100644
--- a/target/arm/syndrome.h
+++ b/target/arm/syndrome.h
@@ -655,11 +655,25 @@ static inline uint32_t syn_breakpoint(int same_el)
     return res;
 }
 
+/*
+ * ISS encoding for an exception from a WF* instruction
+ */
+FIELD(WFX_ISS, TI, 0, 2)
+FIELD(WFX_ISS, RV, 2, 1)
+FIELD(WFX_ISS, RN, 5, 5)
+FIELD(WFX_ISS, COND, 20, 4)
+FIELD(WFX_ISS, CV, 24, 1)
+
 static inline uint32_t syn_wfx(int cv, int cond, int ti, bool is_16bit)
 {
-    return (EC_WFX_TRAP << ARM_EL_EC_SHIFT) |
-           (is_16bit ? 0 : (1 << ARM_EL_IL_SHIFT)) |
-           (cv << 24) | (cond << 20) | ti;
+    uint32_t res = syn_set_ec(0, EC_WFX_TRAP);
+    res = FIELD_DP32(res, SYNDROME, IL, is_16bit ? 0 : 1);
+
+    res = FIELD_DP32(res, WFX_ISS, CV, cv);
+    res = FIELD_DP32(res, WFX_ISS, COND, cond);
+    res = FIELD_DP32(res, WFX_ISS, TI, ti);
+
+    return res;
 }
 
 static inline uint32_t syn_illegalstate(void)
-- 
2.47.3



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

* [RFC PATCH 13/35] target/arm: migrate gcs syndromes to registerfields
  2026-03-20 13:05 [RFC PATCH 00/35] target/arm: fully model WFxT instructions for A-profile Alex Bennée
                   ` (11 preceding siblings ...)
  2026-03-20 13:05 ` [RFC PATCH 12/35] target/arm: migrate wfx " Alex Bennée
@ 2026-03-20 13:05 ` Alex Bennée
  2026-04-05 23:43   ` Richard Henderson
  2026-03-20 13:05 ` [RFC PATCH 14/35] target/arm: migrate memory op " Alex Bennée
                   ` (21 subsequent siblings)
  34 siblings, 1 reply; 74+ messages in thread
From: Alex Bennée @ 2026-03-20 13:05 UTC (permalink / raw)
  To: qemu-devel
  Cc: Alexander Graf, Peter Maydell, qemu-arm, Pedro Barbuda,
	Mohamed Mediouni, Alex Bennée

Added a little comment to explain the RADDR<->ra mismatch.

Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
---
 target/arm/syndrome.h | 38 +++++++++++++++++++++++++++++++++-----
 1 file changed, 33 insertions(+), 5 deletions(-)

diff --git a/target/arm/syndrome.h b/target/arm/syndrome.h
index 503b19b5d02..76f66b3beef 100644
--- a/target/arm/syndrome.h
+++ b/target/arm/syndrome.h
@@ -690,21 +690,49 @@ static inline uint32_t syn_pcalignment(void)
     return res;
 }
 
+/*
+ * ISS encoding for a GCS exception
+ *
+ * Field validity depends on EXTYPE
+ */
+FIELD(GCS_ISS, IT, 0, 5)
+FIELD(GCS_ISS, RN, 5, 5) /* only for non EXLOCK exceptions */
+FIELD(GCS_ISS, RADDR, 10, 5) /* only for GCSSTR/GCSSTTR traps */
+FIELD(GCS_ISS, EXTYPE, 20, 4)
+
 static inline uint32_t syn_gcs_data_check(GCSInstructionType it, int rn)
 {
-    return ((EC_GCS << ARM_EL_EC_SHIFT) | ARM_EL_IL |
-            (GCS_ET_DataCheck << 20) | (rn << 5) | it);
+    uint32_t res = syn_set_ec(0, EC_GCS);
+    res = FIELD_DP32(res, SYNDROME, IL, 1);
+
+    res = FIELD_DP32(res, GCS_ISS, EXTYPE, GCS_ET_DataCheck);
+    res = FIELD_DP32(res, GCS_ISS, RN, rn);
+    res = FIELD_DP32(res, GCS_ISS, IT, it);
+
+    return res;
 }
 
 static inline uint32_t syn_gcs_exlock(void)
 {
-    return (EC_GCS << ARM_EL_EC_SHIFT) | ARM_EL_IL | (GCS_ET_EXLOCK << 20);
+    uint32_t res = syn_set_ec(0, EC_GCS);
+    res = FIELD_DP32(res, SYNDROME, IL, 1);
+
+    res = FIELD_DP32(res, GCS_ISS, EXTYPE, GCS_ET_EXLOCK);
+
+    return res;
 }
 
 static inline uint32_t syn_gcs_gcsstr(int ra, int rn)
 {
-    return ((EC_GCS << ARM_EL_EC_SHIFT) | ARM_EL_IL |
-            (GCS_ET_GCSSTR_GCSSTTR << 20) | (ra << 10) | (rn << 5));
+    uint32_t res = syn_set_ec(0, EC_GCS);
+    res = FIELD_DP32(res, SYNDROME, IL, 1);
+
+    res = FIELD_DP32(res, GCS_ISS, EXTYPE, GCS_ET_GCSSTR_GCSSTTR);
+    /* when ExType == 0b0010 RADDR is the data register */
+    res = FIELD_DP32(res, GCS_ISS, RADDR, ra);
+    res = FIELD_DP32(res, GCS_ISS, RN, rn);
+
+    return res;
 }
 
 static inline uint32_t syn_serror(uint32_t extra)
-- 
2.47.3



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

* [RFC PATCH 14/35] target/arm: migrate memory op syndromes to registerfields
  2026-03-20 13:05 [RFC PATCH 00/35] target/arm: fully model WFxT instructions for A-profile Alex Bennée
                   ` (12 preceding siblings ...)
  2026-03-20 13:05 ` [RFC PATCH 13/35] target/arm: migrate gcs " Alex Bennée
@ 2026-03-20 13:05 ` Alex Bennée
  2026-04-05 23:44   ` Richard Henderson
  2026-03-20 13:05 ` [RFC PATCH 15/35] target/arm: migrate check_hcr_el2_trap to use syndrome helper Alex Bennée
                   ` (20 subsequent siblings)
  34 siblings, 1 reply; 74+ messages in thread
From: Alex Bennée @ 2026-03-20 13:05 UTC (permalink / raw)
  To: qemu-devel
  Cc: Alexander Graf, Peter Maydell, qemu-arm, Pedro Barbuda,
	Mohamed Mediouni, Alex Bennée

Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
---
 target/arm/syndrome.h | 33 +++++++++++++++++++++++++++++----
 1 file changed, 29 insertions(+), 4 deletions(-)

diff --git a/target/arm/syndrome.h b/target/arm/syndrome.h
index 76f66b3beef..2e3121aec9c 100644
--- a/target/arm/syndrome.h
+++ b/target/arm/syndrome.h
@@ -743,14 +743,39 @@ static inline uint32_t syn_serror(uint32_t extra)
     return res;
 }
 
+/*
+ * ISS encoding for an exception from the Memory Copy and Memory Set
+ * instructions.
+ */
+FIELD(MOP_ISS, SIZEREG, 0, 5)
+FIELD(MOP_ISS, SRCREG, 5, 5)
+FIELD(MOP_ISS, DESTREG, 10, 5)
+FIELD(MOP_ISS, FORMATOPT, 16, 2)
+FIELD(MOP_ISS, OPT_A, 16, 1)
+FIELD(MOP_ISS, WRONG_OPT, 17, 1)
+FIELD(MOP_ISS, EPILOGUE, 18, 1)
+FIELD(MOP_ISS, OPTIONS, 19, 4)
+FIELD(MOP_ISS, IS_SETG, 23, 1)
+FIELD(MOP_ISS, MEMINST, 24, 1)
+
 static inline uint32_t syn_mop(bool is_set, bool is_setg, int options,
                                bool epilogue, bool wrong_option, bool option_a,
                                int destreg, int srcreg, int sizereg)
 {
-    return (EC_MOP << ARM_EL_EC_SHIFT) | ARM_EL_IL |
-        (is_set << 24) | (is_setg << 23) | (options << 19) |
-        (epilogue << 18) | (wrong_option << 17) | (option_a << 16) |
-        (destreg << 10) | (srcreg << 5) | sizereg;
+    uint32_t res = syn_set_ec(0, EC_MOP);
+    res = FIELD_DP32(res, SYNDROME, IL, 1);
+
+    res = FIELD_DP32(res, MOP_ISS, MEMINST, is_set);
+    res = FIELD_DP32(res, MOP_ISS, IS_SETG, is_setg);
+    res = FIELD_DP32(res, MOP_ISS, OPTIONS, options);
+    res = FIELD_DP32(res, MOP_ISS, EPILOGUE, epilogue);
+    res = FIELD_DP32(res, MOP_ISS, WRONG_OPT, wrong_option);
+    res = FIELD_DP32(res, MOP_ISS, OPT_A, option_a);
+    res = FIELD_DP32(res, MOP_ISS, DESTREG, destreg);
+    res = FIELD_DP32(res, MOP_ISS, SRCREG, srcreg);
+    res = FIELD_DP32(res, MOP_ISS, SIZEREG, sizereg);
+
+    return res;
 }
 
 
-- 
2.47.3



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

* [RFC PATCH 15/35] target/arm: migrate check_hcr_el2_trap to use syndrome helper
  2026-03-20 13:05 [RFC PATCH 00/35] target/arm: fully model WFxT instructions for A-profile Alex Bennée
                   ` (13 preceding siblings ...)
  2026-03-20 13:05 ` [RFC PATCH 14/35] target/arm: migrate memory op " Alex Bennée
@ 2026-03-20 13:05 ` Alex Bennée
  2026-04-06  0:01   ` Richard Henderson
  2026-03-20 13:05 ` [RFC PATCH 16/35] target/arm: use syndrome helpers in arm_cpu_do_interrupt_aarch32_hyp Alex Bennée
                   ` (19 subsequent siblings)
  34 siblings, 1 reply; 74+ messages in thread
From: Alex Bennée @ 2026-03-20 13:05 UTC (permalink / raw)
  To: qemu-devel
  Cc: Alexander Graf, Peter Maydell, qemu-arm, Pedro Barbuda,
	Mohamed Mediouni, Alex Bennée

It shares the same COPROC_ISS encoding as the other CP traps although
not all the fields are used.

Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
---
 target/arm/syndrome.h       | 16 ++++++++++++++++
 target/arm/tcg/vfp_helper.c |  5 +----
 2 files changed, 17 insertions(+), 4 deletions(-)

diff --git a/target/arm/syndrome.h b/target/arm/syndrome.h
index 2e3121aec9c..4fbc35ce7b0 100644
--- a/target/arm/syndrome.h
+++ b/target/arm/syndrome.h
@@ -251,6 +251,22 @@ FIELD(COPROC_ISS, OP2, 17, 3)
 FIELD(COPROC_ISS, COND, 20, 4)
 FIELD(COPROC_ISS, CV, 24, 1)
 
+static inline uint32_t syn_cp10_rt_trap(int cv, int cond, int opc1,
+                                        int crn, int rt, int isread)
+{
+    uint32_t res = syn_set_ec(0, EC_FPIDTRAP);
+    res = FIELD_DP32(res, SYNDROME, IL, 1);
+
+    res = FIELD_DP32(res, COPROC_ISS, CV, cv);
+    res = FIELD_DP32(res, COPROC_ISS, COND, cond);
+    res = FIELD_DP32(res, COPROC_ISS, OP1, opc1);
+    res = FIELD_DP32(res, COPROC_ISS, CRN, crn);
+    res = FIELD_DP32(res, COPROC_ISS, RT, rt);
+    res = FIELD_DP32(res, COPROC_ISS, ISREAD, isread);
+
+    return res;
+}
+
 static inline uint32_t syn_cp14_rt_trap(int cv, int cond, int opc1, int opc2,
                                         int crn, int crm, int rt, int isread,
                                         bool is_16bit)
diff --git a/target/arm/tcg/vfp_helper.c b/target/arm/tcg/vfp_helper.c
index 45f2eb0930f..e692bc568bd 100644
--- a/target/arm/tcg/vfp_helper.c
+++ b/target/arm/tcg/vfp_helper.c
@@ -1359,10 +1359,7 @@ void HELPER(check_hcr_el2_trap)(CPUARMState *env, uint32_t rt, uint32_t reg)
         g_assert_not_reached();
     }
 
-    syndrome = ((EC_FPIDTRAP << ARM_EL_EC_SHIFT)
-                | ARM_EL_IL
-                | (1 << 24) | (0xe << 20) | (7 << 14)
-                | (reg << 10) | (rt << 5) | 1);
+    syndrome = syn_cp10_rt_trap(1, 0xe, 7, reg, rt, 1);
 
     raise_exception(env, EXCP_HYP_TRAP, syndrome, 2);
 }
-- 
2.47.3



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

* [RFC PATCH 16/35] target/arm: use syndrome helpers in arm_cpu_do_interrupt_aarch32_hyp
  2026-03-20 13:05 [RFC PATCH 00/35] target/arm: fully model WFxT instructions for A-profile Alex Bennée
                   ` (14 preceding siblings ...)
  2026-03-20 13:05 ` [RFC PATCH 15/35] target/arm: migrate check_hcr_el2_trap to use syndrome helper Alex Bennée
@ 2026-03-20 13:05 ` Alex Bennée
  2026-04-06  0:06   ` Richard Henderson
  2026-03-20 13:05 ` [RFC PATCH 17/35] target/arm: use syndrome helpers to set SAME_EL EC bit Alex Bennée
                   ` (18 subsequent siblings)
  34 siblings, 1 reply; 74+ messages in thread
From: Alex Bennée @ 2026-03-20 13:05 UTC (permalink / raw)
  To: qemu-devel
  Cc: Alexander Graf, Peter Maydell, qemu-arm, Pedro Barbuda,
	Mohamed Mediouni, Alex Bennée

One more step towards dropping the old #defines.

Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
---
 target/arm/helper.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/target/arm/helper.c b/target/arm/helper.c
index 7389f2988c4..5ee79f7564f 100644
--- a/target/arm/helper.c
+++ b/target/arm/helper.c
@@ -8898,9 +8898,9 @@ static void arm_cpu_do_interrupt_aarch32_hyp(CPUState *cs)
              */
             if (cs->exception_index == EXCP_PREFETCH_ABORT ||
                 (cs->exception_index == EXCP_DATA_ABORT &&
-                 !(env->exception.syndrome & ARM_EL_ISV)) ||
+                 !(FIELD_EX32(env->exception.syndrome, SYNDROME, IL))) ||
                 syn_get_ec(env->exception.syndrome) == EC_UNCATEGORIZED) {
-                env->exception.syndrome &= ~ARM_EL_IL;
+                env->exception.syndrome = FIELD_DP32(env->exception.syndrome, SYNDROME, IL, 0);
             }
         }
         env->cp15.esr_el[2] = env->exception.syndrome;
-- 
2.47.3



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

* [RFC PATCH 17/35] target/arm: use syndrome helpers to set SAME_EL EC bit
  2026-03-20 13:05 [RFC PATCH 00/35] target/arm: fully model WFxT instructions for A-profile Alex Bennée
                   ` (15 preceding siblings ...)
  2026-03-20 13:05 ` [RFC PATCH 16/35] target/arm: use syndrome helpers in arm_cpu_do_interrupt_aarch32_hyp Alex Bennée
@ 2026-03-20 13:05 ` Alex Bennée
  2026-04-06  0:07   ` Richard Henderson
  2026-03-20 13:05 ` [RFC PATCH 18/35] target/arm: make whpx use syndrome helpers for decode Alex Bennée
                   ` (17 subsequent siblings)
  34 siblings, 1 reply; 74+ messages in thread
From: Alex Bennée @ 2026-03-20 13:05 UTC (permalink / raw)
  To: qemu-devel
  Cc: Alexander Graf, Peter Maydell, qemu-arm, Pedro Barbuda,
	Mohamed Mediouni, Alex Bennée

This removes the last use of ARM_EL_EC_SHIFT.

Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
---
 target/arm/tcg/debug.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/target/arm/tcg/debug.c b/target/arm/tcg/debug.c
index 5214e3c08a8..07a52643e71 100644
--- a/target/arm/tcg/debug.c
+++ b/target/arm/tcg/debug.c
@@ -56,7 +56,7 @@ raise_exception_debug(CPUARMState *env, uint32_t excp, uint32_t syndrome)
      * Similarly for watchpoint and breakpoint matches.
      */
     assert(debug_el >= cur_el);
-    syndrome |= (debug_el == cur_el) << ARM_EL_EC_SHIFT;
+    syndrome |= (debug_el == cur_el) << R_SYNDROME_EC_SHIFT;
     raise_exception(env, excp, syndrome, debug_el);
 }
 
-- 
2.47.3



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

* [RFC PATCH 18/35] target/arm: make whpx use syndrome helpers for decode
  2026-03-20 13:05 [RFC PATCH 00/35] target/arm: fully model WFxT instructions for A-profile Alex Bennée
                   ` (16 preceding siblings ...)
  2026-03-20 13:05 ` [RFC PATCH 17/35] target/arm: use syndrome helpers to set SAME_EL EC bit Alex Bennée
@ 2026-03-20 13:05 ` Alex Bennée
  2026-04-06  0:08   ` Richard Henderson
  2026-03-20 13:05 ` [RFC PATCH 19/35] target/arm: make hvf " Alex Bennée
                   ` (16 subsequent siblings)
  34 siblings, 1 reply; 74+ messages in thread
From: Alex Bennée @ 2026-03-20 13:05 UTC (permalink / raw)
  To: qemu-devel
  Cc: Alexander Graf, Peter Maydell, qemu-arm, Pedro Barbuda,
	Mohamed Mediouni, Alex Bennée

Rather than open coding a bunch of shifts and masks we can use the
syndrome definitions. While we are at it assert it really is a
EC_DATAABORT.

Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
---
 target/arm/whpx/whpx-all.c | 13 +++++++------
 1 file changed, 7 insertions(+), 6 deletions(-)

diff --git a/target/arm/whpx/whpx-all.c b/target/arm/whpx/whpx-all.c
index 513551bec1b..f5646e7127e 100644
--- a/target/arm/whpx/whpx-all.c
+++ b/target/arm/whpx/whpx-all.c
@@ -356,15 +356,16 @@ static int whpx_handle_mmio(CPUState *cpu, WHV_MEMORY_ACCESS_CONTEXT *ctx)
 {
     uint64_t syndrome = ctx->Syndrome;
 
-    bool isv = syndrome & ARM_EL_ISV;
-    bool iswrite = (syndrome >> 6) & 1;
-    bool sse = (syndrome >> 21) & 1;
-    uint32_t sas = (syndrome >> 22) & 3;
+    bool isv = FIELD_EX32(syndrome, DABORT_ISS, ISV);
+    bool iswrite = FIELD_EX32(syndrome, DABORT_ISS, WNR);
+    bool sse = FIELD_EX32(syndrome, DABORT_ISS, SSE);
+    uint32_t sas = FIELD_EX32(syndrome, DABORT_ISS, SAS);
     uint32_t len = 1 << sas;
-    uint32_t srt = (syndrome >> 16) & 0x1f;
-    uint32_t cm = (syndrome >> 8) & 0x1;
+    uint32_t srt = FIELD_EX32(syndrome, DABORT_ISS, SRT);
+    uint32_t cm = FIELD_EX32(syndrome, DABORT_ISS, CM);
     uint64_t val = 0;
 
+    assert(syn_get_ec(syndrome) == EC_DATAABORT);
     assert(!cm);
     assert(isv);
 
-- 
2.47.3



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

* [RFC PATCH 19/35] target/arm: make hvf use syndrome helpers for decode
  2026-03-20 13:05 [RFC PATCH 00/35] target/arm: fully model WFxT instructions for A-profile Alex Bennée
                   ` (17 preceding siblings ...)
  2026-03-20 13:05 ` [RFC PATCH 18/35] target/arm: make whpx use syndrome helpers for decode Alex Bennée
@ 2026-03-20 13:05 ` Alex Bennée
  2026-04-06  0:08   ` Richard Henderson
  2026-03-20 13:05 ` [RFC PATCH 20/35] target/arm: use syndrome helpers in merge_syn_data_abort Alex Bennée
                   ` (15 subsequent siblings)
  34 siblings, 1 reply; 74+ messages in thread
From: Alex Bennée @ 2026-03-20 13:05 UTC (permalink / raw)
  To: qemu-devel
  Cc: Alexander Graf, Peter Maydell, qemu-arm, Pedro Barbuda,
	Mohamed Mediouni, Alex Bennée

Rather than open coding a bunch of shifts and masks we can use the
syndrome definitions.

Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
---
 target/arm/hvf/hvf.c | 14 +++++++-------
 1 file changed, 7 insertions(+), 7 deletions(-)

diff --git a/target/arm/hvf/hvf.c b/target/arm/hvf/hvf.c
index 5fc8f6bbbd9..1c1c31f0b15 100644
--- a/target/arm/hvf/hvf.c
+++ b/target/arm/hvf/hvf.c
@@ -2123,14 +2123,14 @@ static int hvf_handle_exception(CPUState *cpu, hv_vcpu_exit_exception_t *excp)
         break;
     }
     case EC_DATAABORT: {
-        bool isv = syndrome & ARM_EL_ISV;
-        bool iswrite = (syndrome >> 6) & 1;
-        bool s1ptw = (syndrome >> 7) & 1;
-        bool sse = (syndrome >> 21) & 1;
-        uint32_t sas = (syndrome >> 22) & 3;
+        bool isv = FIELD_EX32(syndrome, DABORT_ISS, ISV);
+        bool iswrite = FIELD_EX32(syndrome, DABORT_ISS, WNR);
+        bool s1ptw = FIELD_EX32(syndrome, DABORT_ISS, S1PTW);
+        bool sse = FIELD_EX32(syndrome, DABORT_ISS, SSE);
+        uint32_t sas = FIELD_EX32(syndrome, DABORT_ISS, SAS);
         uint32_t len = 1 << sas;
-        uint32_t srt = (syndrome >> 16) & 0x1f;
-        uint32_t cm = (syndrome >> 8) & 0x1;
+        uint32_t srt = FIELD_EX32(syndrome, DABORT_ISS, SRT);
+        uint32_t cm = FIELD_EX32(syndrome, DABORT_ISS, CM);
         uint64_t val = 0;
         uint64_t ipa = excp->physical_address;
         AddressSpace *as = cpu_get_address_space(cpu, ARMASIdx_NS);
-- 
2.47.3



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

* [RFC PATCH 20/35] target/arm: use syndrome helpers in merge_syn_data_abort
  2026-03-20 13:05 [RFC PATCH 00/35] target/arm: fully model WFxT instructions for A-profile Alex Bennée
                   ` (18 preceding siblings ...)
  2026-03-20 13:05 ` [RFC PATCH 19/35] target/arm: make hvf " Alex Bennée
@ 2026-03-20 13:05 ` Alex Bennée
  2026-04-06  0:15   ` Richard Henderson
  2026-03-20 13:05 ` [RFC PATCH 21/35] target/arm: use syndrome helpers to query VNCR bit Alex Bennée
                   ` (14 subsequent siblings)
  34 siblings, 1 reply; 74+ messages in thread
From: Alex Bennée @ 2026-03-20 13:05 UTC (permalink / raw)
  To: qemu-devel
  Cc: Alexander Graf, Peter Maydell, qemu-arm, Pedro Barbuda,
	Mohamed Mediouni, Alex Bennée

One more step to removing the old defines.

Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
---
 target/arm/tcg/tlb_helper.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/target/arm/tcg/tlb_helper.c b/target/arm/tcg/tlb_helper.c
index 565954269f9..c74d8e785a6 100644
--- a/target/arm/tcg/tlb_helper.c
+++ b/target/arm/tcg/tlb_helper.c
@@ -56,7 +56,7 @@ static inline uint64_t merge_syn_data_abort(uint32_t template_syn,
          */
         assert(!fi->stage2);
         syn = syn_data_abort_vncr(fi->ea, is_write, fsc);
-    } else if (!(template_syn & ARM_EL_ISV) || target_el != 2
+    } else if (!FIELD_EX32(template_syn, DABORT_ISS, ISV) || target_el != 2
         || fi->s1ptw || !fi->stage2) {
         syn = syn_data_abort_no_iss(same_el, 0,
                                     fi->ea, 0, fi->s1ptw, is_write, fsc);
-- 
2.47.3



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

* [RFC PATCH 21/35] target/arm: use syndrome helpers to query VNCR bit
  2026-03-20 13:05 [RFC PATCH 00/35] target/arm: fully model WFxT instructions for A-profile Alex Bennée
                   ` (19 preceding siblings ...)
  2026-03-20 13:05 ` [RFC PATCH 20/35] target/arm: use syndrome helpers in merge_syn_data_abort Alex Bennée
@ 2026-03-20 13:05 ` Alex Bennée
  2026-04-06  0:17   ` Richard Henderson
  2026-03-20 13:05 ` [RFC PATCH 22/35] target/arm: remove old syndrome defines Alex Bennée
                   ` (13 subsequent siblings)
  34 siblings, 1 reply; 74+ messages in thread
From: Alex Bennée @ 2026-03-20 13:05 UTC (permalink / raw)
  To: qemu-devel
  Cc: Alexander Graf, Peter Maydell, qemu-arm, Pedro Barbuda,
	Mohamed Mediouni, Alex Bennée

These are only valid for data abort syndromes.

Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
---
 target/arm/tcg/tlb_helper.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/target/arm/tcg/tlb_helper.c b/target/arm/tcg/tlb_helper.c
index c74d8e785a6..bbe1e70bc43 100644
--- a/target/arm/tcg/tlb_helper.c
+++ b/target/arm/tcg/tlb_helper.c
@@ -48,7 +48,7 @@ static inline uint64_t merge_syn_data_abort(uint32_t template_syn,
      * ST64BV, or ST64BV0 insns report syndrome info even for stage-1
      * faults and regardless of the target EL.
      */
-    if (template_syn & ARM_EL_VNCR) {
+    if (FIELD_EX32(template_syn, DABORT_ISS, VNCR)) {
         /*
          * FEAT_NV2 faults on accesses via VNCR_EL2 are a special case:
          * they are always reported as "same EL", even though we are going
@@ -190,7 +190,7 @@ void arm_deliver_fault(ARMCPU *cpu, vaddr addr,
      * because we masked that out in disas_set_insn_syndrome())
      */
     bool is_vncr = (access_type != MMU_INST_FETCH) &&
-        (env->exception.syndrome & ARM_EL_VNCR);
+        FIELD_EX32(env->exception.syndrome, DABORT_ISS, VNCR);
 
     if (is_vncr) {
         /* FEAT_NV2 faults on accesses via VNCR_EL2 go to EL2 */
-- 
2.47.3



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

* [RFC PATCH 22/35] target/arm: remove old syndrome defines
  2026-03-20 13:05 [RFC PATCH 00/35] target/arm: fully model WFxT instructions for A-profile Alex Bennée
                   ` (20 preceding siblings ...)
  2026-03-20 13:05 ` [RFC PATCH 21/35] target/arm: use syndrome helpers to query VNCR bit Alex Bennée
@ 2026-03-20 13:05 ` Alex Bennée
  2026-04-06  0:17   ` Richard Henderson
  2026-03-20 13:05 ` [RFC PATCH 23/35] target/arm: report register in WFIT syndromes Alex Bennée
                   ` (12 subsequent siblings)
  34 siblings, 1 reply; 74+ messages in thread
From: Alex Bennée @ 2026-03-20 13:05 UTC (permalink / raw)
  To: qemu-devel
  Cc: Alexander Graf, Peter Maydell, qemu-arm, Pedro Barbuda,
	Mohamed Mediouni, Alex Bennée

Now everything is defined with registerfields we can drop the old
defines.

Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
---
 target/arm/syndrome.h | 10 ----------
 1 file changed, 10 deletions(-)

diff --git a/target/arm/syndrome.h b/target/arm/syndrome.h
index 4fbc35ce7b0..1887467b719 100644
--- a/target/arm/syndrome.h
+++ b/target/arm/syndrome.h
@@ -106,16 +106,6 @@ typedef enum {
     GCS_IT_GCSPOPX = 9,
 } GCSInstructionType;
 
-#define ARM_EL_EC_LENGTH 6
-#define ARM_EL_EC_SHIFT 26
-#define ARM_EL_IL_SHIFT 25
-#define ARM_EL_ISV_SHIFT 24
-#define ARM_EL_IL (1 << ARM_EL_IL_SHIFT)
-#define ARM_EL_ISV (1 << ARM_EL_ISV_SHIFT)
-
-/* In the Data Abort syndrome */
-#define ARM_EL_VNCR (1 << 13)
-
 static inline uint32_t syn_get_ec(uint32_t syn)
 {
     return FIELD_EX32(syn, SYNDROME, EC);
-- 
2.47.3



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

* [RFC PATCH 23/35] target/arm: report register in WFIT syndromes
  2026-03-20 13:05 [RFC PATCH 00/35] target/arm: fully model WFxT instructions for A-profile Alex Bennée
                   ` (21 preceding siblings ...)
  2026-03-20 13:05 ` [RFC PATCH 22/35] target/arm: remove old syndrome defines Alex Bennée
@ 2026-03-20 13:05 ` Alex Bennée
  2026-04-06  0:24   ` Richard Henderson
  2026-03-20 13:05 ` [RFC PATCH 24/35] target/arm: remove event_register check from arm_cpu_has_work Alex Bennée
                   ` (11 subsequent siblings)
  34 siblings, 1 reply; 74+ messages in thread
From: Alex Bennée @ 2026-03-20 13:05 UTC (permalink / raw)
  To: qemu-devel
  Cc: Alexander Graf, Peter Maydell, qemu-arm, Pedro Barbuda,
	Mohamed Mediouni, Alex Bennée

Pass the register number (rd) to the wfit helper and report it in the
syndrome ISS. This also includes the correction of the TI bits for
WFIT traps to 0b10.

TODO: split the helper flags

Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
---
 target/arm/syndrome.h          | 4 +++-
 target/arm/tcg/helper-defs.h   | 2 +-
 target/arm/tcg/op_helper.c     | 7 ++++---
 target/arm/tcg/translate-a64.c | 2 +-
 4 files changed, 9 insertions(+), 6 deletions(-)

diff --git a/target/arm/syndrome.h b/target/arm/syndrome.h
index 1887467b719..f303c41d71a 100644
--- a/target/arm/syndrome.h
+++ b/target/arm/syndrome.h
@@ -670,7 +670,7 @@ FIELD(WFX_ISS, RN, 5, 5)
 FIELD(WFX_ISS, COND, 20, 4)
 FIELD(WFX_ISS, CV, 24, 1)
 
-static inline uint32_t syn_wfx(int cv, int cond, int ti, bool is_16bit)
+static inline uint32_t syn_wfx(int cv, int cond, int rn, int rv, int ti, bool is_16bit)
 {
     uint32_t res = syn_set_ec(0, EC_WFX_TRAP);
     res = FIELD_DP32(res, SYNDROME, IL, is_16bit ? 0 : 1);
@@ -678,6 +678,8 @@ static inline uint32_t syn_wfx(int cv, int cond, int ti, bool is_16bit)
     res = FIELD_DP32(res, WFX_ISS, CV, cv);
     res = FIELD_DP32(res, WFX_ISS, COND, cond);
     res = FIELD_DP32(res, WFX_ISS, TI, ti);
+    res = FIELD_DP32(res, WFX_ISS, RN, rn);
+    res = FIELD_DP32(res, WFX_ISS, RV, rv);
 
     return res;
 }
diff --git a/target/arm/tcg/helper-defs.h b/target/arm/tcg/helper-defs.h
index 5a10a9fba3b..a05f2258f29 100644
--- a/target/arm/tcg/helper-defs.h
+++ b/target/arm/tcg/helper-defs.h
@@ -55,7 +55,7 @@ DEF_HELPER_2(exception_pc_alignment, noreturn, env, vaddr)
 DEF_HELPER_1(setend, void, env)
 DEF_HELPER_2(wfi, void, env, i32)
 DEF_HELPER_1(wfe, void, env)
-DEF_HELPER_2(wfit, void, env, i64)
+DEF_HELPER_2(wfit, void, env, i32)
 DEF_HELPER_1(yield, void, env)
 DEF_HELPER_1(pre_hvc, void, env)
 DEF_HELPER_2(pre_smc, void, env, i32)
diff --git a/target/arm/tcg/op_helper.c b/target/arm/tcg/op_helper.c
index aa14f15eb62..635c538ed4b 100644
--- a/target/arm/tcg/op_helper.c
+++ b/target/arm/tcg/op_helper.c
@@ -399,7 +399,7 @@ void HELPER(wfi)(CPUARMState *env, uint32_t insn_len)
             env->regs[15] -= insn_len;
         }
 
-        raise_exception(env, excp, syn_wfx(1, 0xe, 0, insn_len == 2),
+        raise_exception(env, excp, syn_wfx(1, 0xe, 0, 0, 0, insn_len == 2),
                         target_el);
     }
 
@@ -409,7 +409,7 @@ void HELPER(wfi)(CPUARMState *env, uint32_t insn_len)
 #endif
 }
 
-void HELPER(wfit)(CPUARMState *env, uint64_t timeout)
+void HELPER(wfit)(CPUARMState *env, uint32_t rd)
 {
 #ifdef CONFIG_USER_ONLY
     /*
@@ -428,6 +428,7 @@ void HELPER(wfit)(CPUARMState *env, uint64_t timeout)
     int target_el = check_wfx_trap(env, false, &excp);
     /* The WFIT should time out when CNTVCT_EL0 >= the specified value. */
     uint64_t cntval = gt_get_countervalue(env);
+    uint64_t timeout = env->xregs[rd];
     /*
      * We want the value that we would get if we read CNTVCT_EL0 from
      * the current exception level, so the direct_access offset, not
@@ -448,7 +449,7 @@ void HELPER(wfit)(CPUARMState *env, uint64_t timeout)
 
     if (target_el) {
         env->pc -= 4;
-        raise_exception(env, excp, syn_wfx(1, 0xe, 2, false), target_el);
+        raise_exception(env, excp, syn_wfx(1, 0xe, rd, 1, 2, false), target_el);
     }
 
     if (uadd64_overflow(timeout, offset, &nexttick)) {
diff --git a/target/arm/tcg/translate-a64.c b/target/arm/tcg/translate-a64.c
index 5d261a5e32b..073454b9195 100644
--- a/target/arm/tcg/translate-a64.c
+++ b/target/arm/tcg/translate-a64.c
@@ -2064,7 +2064,7 @@ static bool trans_WFIT(DisasContext *s, arg_WFIT *a)
     }
 
     gen_a64_update_pc(s, 4);
-    gen_helper_wfit(tcg_env, cpu_reg(s, a->rd));
+    gen_helper_wfit(tcg_env, tcg_constant_i32(a->rd));
     /* Go back to the main loop to check for interrupts */
     s->base.is_jmp = DISAS_EXIT;
     return true;
-- 
2.47.3



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

* [RFC PATCH 24/35] target/arm: remove event_register check from arm_cpu_has_work
  2026-03-20 13:05 [RFC PATCH 00/35] target/arm: fully model WFxT instructions for A-profile Alex Bennée
                   ` (22 preceding siblings ...)
  2026-03-20 13:05 ` [RFC PATCH 23/35] target/arm: report register in WFIT syndromes Alex Bennée
@ 2026-03-20 13:05 ` Alex Bennée
  2026-04-10  8:47   ` Peter Maydell
  2026-03-20 13:05 ` [RFC PATCH 25/35] target/arm: redefine event stream fields Alex Bennée
                   ` (10 subsequent siblings)
  34 siblings, 1 reply; 74+ messages in thread
From: Alex Bennée @ 2026-03-20 13:05 UTC (permalink / raw)
  To: qemu-devel
  Cc: Alexander Graf, Peter Maydell, qemu-arm, Pedro Barbuda,
	Mohamed Mediouni, Alex Bennée

The generation of events are not indications of work to be done and
importantly for the case of WFI instructions not a reason to wake up.
Remove the check.

Fixes: d238858bff6 (target/arm: Implement WFE, SEV and SEVONPEND for Cortex-M)
Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
---
 target/arm/cpu.c | 6 ------
 1 file changed, 6 deletions(-)

diff --git a/target/arm/cpu.c b/target/arm/cpu.c
index 98d09ac0656..d51599dfdab 100644
--- a/target/arm/cpu.c
+++ b/target/arm/cpu.c
@@ -144,12 +144,6 @@ static bool arm_cpu_has_work(CPUState *cs)
 {
     ARMCPU *cpu = ARM_CPU(cs);
 
-    if (arm_feature(&cpu->env, ARM_FEATURE_M)) {
-        if (cpu->env.event_register) {
-            return true;
-        }
-    }
-
     return (cpu->power_state != PSCI_OFF)
         && cpu_test_interrupt(cs,
                CPU_INTERRUPT_FIQ | CPU_INTERRUPT_HARD
-- 
2.47.3



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

* [RFC PATCH 25/35] target/arm: redefine event stream fields
  2026-03-20 13:05 [RFC PATCH 00/35] target/arm: fully model WFxT instructions for A-profile Alex Bennée
                   ` (23 preceding siblings ...)
  2026-03-20 13:05 ` [RFC PATCH 24/35] target/arm: remove event_register check from arm_cpu_has_work Alex Bennée
@ 2026-03-20 13:05 ` Alex Bennée
  2026-04-06  0:30   ` Richard Henderson
  2026-03-20 13:05 ` [RFC PATCH 26/35] target/arm: add gt_calc_next_event_stream Alex Bennée
                   ` (9 subsequent siblings)
  34 siblings, 1 reply; 74+ messages in thread
From: Alex Bennée @ 2026-03-20 13:05 UTC (permalink / raw)
  To: qemu-devel
  Cc: Alexander Graf, Peter Maydell, qemu-arm, Pedro Barbuda,
	Mohamed Mediouni, Alex Bennée

The event stream control bits are the same for both CNTHCTL and
CNTKCTL so rather than duplicating the definitions rename them to be
useful in both cases.

We will need these in a later commit when we start implementing event
streams.

Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
---
 target/arm/internals.h | 11 +++++++----
 target/arm/helper.c    |  8 ++++----
 2 files changed, 11 insertions(+), 8 deletions(-)

diff --git a/target/arm/internals.h b/target/arm/internals.h
index 8ec27508473..2296ac9cfb6 100644
--- a/target/arm/internals.h
+++ b/target/arm/internals.h
@@ -263,14 +263,17 @@ FIELD(VSTCR, SA, 30, 1)
  * have different bit definitions, and EL1PCTEN might be
  * bit 0 or bit 10. We use _E2H1 and _E2H0 suffixes to
  * disambiguate if necessary.
+ *
+ * The event stream bits (EVN*) are in the same position for
+ * CNTKCTL_EL1/CTNKCTL.
  */
 FIELD(CNTHCTL, EL0PCTEN_E2H1, 0, 1)
 FIELD(CNTHCTL, EL0VCTEN_E2H1, 1, 1)
 FIELD(CNTHCTL, EL1PCTEN_E2H0, 0, 1)
 FIELD(CNTHCTL, EL1PCEN_E2H0, 1, 1)
-FIELD(CNTHCTL, EVNTEN, 2, 1)
-FIELD(CNTHCTL, EVNTDIR, 3, 1)
-FIELD(CNTHCTL, EVNTI, 4, 4)
+FIELD(CNTxCTL, EVNTEN, 2, 1)
+FIELD(CNTxCTL, EVNTDIR, 3, 1)
+FIELD(CNTxCTL, EVNTI, 4, 4)
 FIELD(CNTHCTL, EL0VTEN, 8, 1)
 FIELD(CNTHCTL, EL0PTEN, 9, 1)
 FIELD(CNTHCTL, EL1PCTEN_E2H1, 10, 1)
@@ -280,7 +283,7 @@ FIELD(CNTHCTL, EL1TVT, 13, 1)
 FIELD(CNTHCTL, EL1TVCT, 14, 1)
 FIELD(CNTHCTL, EL1NVPCT, 15, 1)
 FIELD(CNTHCTL, EL1NVVCT, 16, 1)
-FIELD(CNTHCTL, EVNTIS, 17, 1)
+FIELD(CNTxCTL, EVNTIS, 17, 1)
 FIELD(CNTHCTL, CNTVMASK, 18, 1)
 FIELD(CNTHCTL, CNTPMASK, 19, 1)
 
diff --git a/target/arm/helper.c b/target/arm/helper.c
index 5ee79f7564f..ba6db46d453 100644
--- a/target/arm/helper.c
+++ b/target/arm/helper.c
@@ -1746,9 +1746,9 @@ static void gt_cnthctl_write(CPUARMState *env, const ARMCPRegInfo *ri,
     uint32_t valid_mask =
         R_CNTHCTL_EL0PCTEN_E2H1_MASK |
         R_CNTHCTL_EL0VCTEN_E2H1_MASK |
-        R_CNTHCTL_EVNTEN_MASK |
-        R_CNTHCTL_EVNTDIR_MASK |
-        R_CNTHCTL_EVNTI_MASK |
+        R_CNTxCTL_EVNTEN_MASK |
+        R_CNTxCTL_EVNTDIR_MASK |
+        R_CNTxCTL_EVNTI_MASK |
         R_CNTHCTL_EL0VTEN_MASK |
         R_CNTHCTL_EL0PTEN_MASK |
         R_CNTHCTL_EL1PCTEN_E2H1_MASK |
@@ -1763,7 +1763,7 @@ static void gt_cnthctl_write(CPUARMState *env, const ARMCPRegInfo *ri,
             R_CNTHCTL_EL1TVCT_MASK |
             R_CNTHCTL_EL1NVPCT_MASK |
             R_CNTHCTL_EL1NVVCT_MASK |
-            R_CNTHCTL_EVNTIS_MASK;
+            R_CNTxCTL_EVNTIS_MASK;
     }
     if (cpu_isar_feature(aa64_ecv, cpu)) {
         valid_mask |= R_CNTHCTL_ECV_MASK;
-- 
2.47.3



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

* [RFC PATCH 26/35] target/arm: add gt_calc_next_event_stream
  2026-03-20 13:05 [RFC PATCH 00/35] target/arm: fully model WFxT instructions for A-profile Alex Bennée
                   ` (24 preceding siblings ...)
  2026-03-20 13:05 ` [RFC PATCH 25/35] target/arm: redefine event stream fields Alex Bennée
@ 2026-03-20 13:05 ` Alex Bennée
  2026-04-06  0:34   ` Richard Henderson
  2026-03-20 13:05 ` [RFC PATCH 27/35] target/arm: wrap event_register in a union Alex Bennée
                   ` (8 subsequent siblings)
  34 siblings, 1 reply; 74+ messages in thread
From: Alex Bennée @ 2026-03-20 13:05 UTC (permalink / raw)
  To: qemu-devel
  Cc: Alexander Graf, Peter Maydell, qemu-arm, Pedro Barbuda,
	Mohamed Mediouni, Alex Bennée

Two generic timers (K and H) are capable of generating timer event
stream events. Provide a helper to calculate when the nearest one will
happen. This will eventually be used when implementing WFE/WFET.

Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
---
 target/arm/cpu.h    | 10 ++++++
 target/arm/helper.c | 85 +++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 95 insertions(+)

diff --git a/target/arm/cpu.h b/target/arm/cpu.h
index 657ff4ab20b..bf6cf74c2e1 100644
--- a/target/arm/cpu.h
+++ b/target/arm/cpu.h
@@ -1208,6 +1208,16 @@ void arm_gt_sel2vtimer_cb(void *opaque);
 unsigned int gt_cntfrq_period_ns(ARMCPU *cpu);
 void gt_rme_post_el_change(ARMCPU *cpu, void *opaque);
 
+/**
+ * gt_calc_next_event_stream() - calculate and arm event stream timer
+ * @env: CPUArmState
+ *
+ * Calculate the next event stream time and return it. Returns -1 if
+ * no event streams are enabled. It is up to the WFE helpers to decide
+ * on the next time.
+ */
+int64_t gt_calc_next_event_stream(CPUARMState *env);
+
 #define ARM_AFF0_SHIFT 0
 #define ARM_AFF0_MASK  (0xFFULL << ARM_AFF0_SHIFT)
 #define ARM_AFF1_SHIFT 8
diff --git a/target/arm/helper.c b/target/arm/helper.c
index ba6db46d453..3627ffcdcfd 100644
--- a/target/arm/helper.c
+++ b/target/arm/helper.c
@@ -25,6 +25,7 @@
 #include "exec/icount.h"
 #include "system/kvm.h"
 #include "system/tcg.h"
+#include "system/cpus.h"
 #include "qapi/error.h"
 #include "qemu/guest-random.h"
 #ifdef CONFIG_TCG
@@ -2022,6 +2023,90 @@ void arm_gt_hvtimer_cb(void *opaque)
     gt_recalc_timer(cpu, GTIMER_HYPVIRT);
 }
 
+/*
+ * Event Stream events don't do anything apart from wake up sleeping
+ * cores. These helpers calculate the next event stream event time so
+ * the WFE helper can decide when its next wake up tick will be.
+ */
+static int64_t gt_recalc_one_evt(CPUARMState *env, uint32_t control, uint64_t offset)
+{
+    ARMCPU *cpu = env_archcpu(env);
+    bool evnten = FIELD_EX32(control, CNTxCTL, EVNTEN);
+
+    if (evnten) {
+        int evnti = FIELD_EX32(control, CNTxCTL, EVNTI);
+        bool evntis = FIELD_EX32(control, CNTxCTL, EVNTIS);
+        bool evntdir = FIELD_EX32(control, CNTxCTL, EVNTDIR);
+        /*
+         * To figure out when the next event timer should fire we need
+         * to calculate which bit of the counter we want to flip and
+         * which transition counts.
+         *
+         * So we calculate 1 << bit - current lower bits and then add
+         * 1 << bit if the bit needs to flip twice to meet evntdir
+         */
+        int bit = evntis ? evnti + 8 : evnti;
+        uint64_t count = gt_get_countervalue(env) - offset;
+        uint64_t target_bit = BIT_ULL(bit);
+        uint64_t lower_bits = MAKE_64BIT_MASK(0, bit - 1);
+        uint64_t next_tick = target_bit - (count & lower_bits);
+        uint64_t abstick;
+
+        /* do we need to bit flip twice? */
+        if (((count & target_bit) != 0) ^ evntdir) {
+            next_tick += target_bit;
+        }
+
+        /*
+         * Note that the desired next expiry time might be beyond the
+         * signed-64-bit range of a QEMUTimer -- in this case we just
+         * set the timer for as far in the future as possible. When the
+         * timer expires we will reset the timer for any remaining period.
+         */
+        if (uadd64_overflow(next_tick, offset, &abstick)) {
+            abstick = UINT64_MAX;
+        }
+        if (abstick > INT64_MAX / gt_cntfrq_period_ns(cpu)) {
+            return INT64_MAX;
+        } else {
+            return abstick;
+        }
+    }
+
+    return -1;
+}
+
+int64_t gt_calc_next_event_stream(CPUARMState *env)
+{
+    ARMCPU *cpu = env_archcpu(env);
+    uint64_t hcr = arm_hcr_el2_eff(env);
+    int64_t next_time = -1;
+    uint64_t offset;
+
+    /* Unless we are missing EL2 this can generate events */
+    if (arm_feature(env, ARM_FEATURE_EL2)) {
+        offset = gt_direct_access_timer_offset(env, GTIMER_PHYS);
+        next_time = gt_recalc_one_evt(env, env->cp15.cnthctl_el2, offset);
+    }
+
+    /* Event stream events from virtual counter enabled? */
+    if (!cpu_isar_feature(aa64_vh, cpu) ||
+        !((hcr & (HCR_E2H | HCR_TGE)) == (HCR_E2H | HCR_TGE))) {
+        int64_t next_virt_time;
+        offset = gt_direct_access_timer_offset(env, GTIMER_VIRT);
+        next_virt_time = gt_recalc_one_evt(env, env->cp15.c14_cntkctl, offset);
+
+        /* is this earlier than the next physical event? */
+        if (next_virt_time > 0) {
+            if (next_time < 0 || next_virt_time < next_time) {
+                next_time = next_virt_time;
+            }
+        }
+    }
+
+    return next_time;
+}
+
 static const ARMCPRegInfo generic_timer_cp_reginfo[] = {
     /*
      * Note that CNTFRQ is purely reads-as-written for the benefit
-- 
2.47.3



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

* [RFC PATCH 27/35] target/arm: wrap event_register in a union
  2026-03-20 13:05 [RFC PATCH 00/35] target/arm: fully model WFxT instructions for A-profile Alex Bennée
                   ` (25 preceding siblings ...)
  2026-03-20 13:05 ` [RFC PATCH 26/35] target/arm: add gt_calc_next_event_stream Alex Bennée
@ 2026-03-20 13:05 ` Alex Bennée
  2026-04-06  0:37   ` Richard Henderson
  2026-03-20 13:05 ` [RFC PATCH 28/35] target/arm: ensure aarch64 DISAS_WFE will exit Alex Bennée
                   ` (7 subsequent siblings)
  34 siblings, 1 reply; 74+ messages in thread
From: Alex Bennée @ 2026-03-20 13:05 UTC (permalink / raw)
  To: qemu-devel
  Cc: Alexander Graf, Peter Maydell, qemu-arm, Pedro Barbuda,
	Mohamed Mediouni, Alex Bennée

While the event register is either set or not due to the
implementation defined nature of bool types we can't set it directly
from TCG code. By wrapping in a union we can alias a 32 bit value to
the bool in a future patch.

Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
---
 target/arm/cpu.h           | 9 +++++++--
 hw/intc/armv7m_nvic.c      | 2 +-
 target/arm/machine.c       | 4 ++--
 target/arm/tcg/m_helper.c  | 4 ++--
 target/arm/tcg/op_helper.c | 6 +++---
 5 files changed, 15 insertions(+), 10 deletions(-)

diff --git a/target/arm/cpu.h b/target/arm/cpu.h
index bf6cf74c2e1..9c25b60ae83 100644
--- a/target/arm/cpu.h
+++ b/target/arm/cpu.h
@@ -763,9 +763,14 @@ typedef struct CPUArchState {
     /*
      * The event register is shared by all ARM profiles (A/R/M),
      * so it is stored in the top-level CPU state.
-     * WFE/SEV handling is currently implemented only for M-profile.
+     *
+     * It is treated as a boolean but we need the union so we can set
+     * it from TCG.
      */
-    bool event_register;
+    union {
+        bool as_bool;
+        uint32_t as_uint32;
+    } event_register;
 
     /* Fields up to this point are cleared by a CPU reset */
     struct {} end_reset_fields;
diff --git a/hw/intc/armv7m_nvic.c b/hw/intc/armv7m_nvic.c
index a7651f831eb..d630f80e51a 100644
--- a/hw/intc/armv7m_nvic.c
+++ b/hw/intc/armv7m_nvic.c
@@ -238,7 +238,7 @@ static void nvic_update_pending_state(NVICState *s, VecInfo *vec,
         int scr_bank = exc_targets_secure(s, irq) ? M_REG_S : M_REG_NS;
         /* SEVONPEND: interrupt going to pending is a WFE wakeup event */
         if (s->cpu->env.v7m.scr[scr_bank] & R_V7M_SCR_SEVONPEND_MASK) {
-            s->cpu->env.event_register = true;
+            s->cpu->env.event_register.as_bool = true;
             qemu_cpu_kick(CPU(s->cpu));
         }
     }
diff --git a/target/arm/machine.c b/target/arm/machine.c
index b0e499515cf..844e6a37c77 100644
--- a/target/arm/machine.c
+++ b/target/arm/machine.c
@@ -514,7 +514,7 @@ static bool event_needed(void *opaque)
 {
     ARMCPU *cpu = opaque;
 
-    return cpu->env.event_register;
+    return cpu->env.event_register.as_bool;
 }
 
 static const VMStateDescription vmstate_event = {
@@ -523,7 +523,7 @@ static const VMStateDescription vmstate_event = {
     .minimum_version_id = 1,
     .needed = event_needed,
     .fields = (const VMStateField[]) {
-        VMSTATE_BOOL(env.event_register, ARMCPU),
+        VMSTATE_BOOL(env.event_register.as_bool, ARMCPU),
         VMSTATE_END_OF_LIST()
     }
 };
diff --git a/target/arm/tcg/m_helper.c b/target/arm/tcg/m_helper.c
index a0cb8cb021e..3259e624e02 100644
--- a/target/arm/tcg/m_helper.c
+++ b/target/arm/tcg/m_helper.c
@@ -964,7 +964,7 @@ static void v7m_exception_taken(ARMCPU *cpu, uint32_t lr, bool dotailchain,
      * take (which might now be the derived exception).
      * Exception entry sets the event register (ARM ARM R_BPBR)
      */
-    env->event_register = true;
+    env->event_register.as_bool = true;
     armv7m_nvic_acknowledge_irq(env->nvic);
 
     /* Switch to target security state -- must do this before writing SPSEL */
@@ -1910,7 +1910,7 @@ static void do_v7m_exception_exit(ARMCPU *cpu)
     arm_rebuild_hflags(env);
 
     /* Exception return sets the event register (ARM ARM R_BPBR) */
-    env->event_register = true;
+    env->event_register.as_bool = true;
     qemu_log_mask(CPU_LOG_INT, "...successful exception return\n");
 }
 
diff --git a/target/arm/tcg/op_helper.c b/target/arm/tcg/op_helper.c
index 635c538ed4b..b5c8024ace7 100644
--- a/target/arm/tcg/op_helper.c
+++ b/target/arm/tcg/op_helper.c
@@ -476,7 +476,7 @@ void HELPER(sev)(CPUARMState *env)
     CPU_FOREACH(cs) {
         ARMCPU *target_cpu = ARM_CPU(cs);
         if (arm_feature(&target_cpu->env, ARM_FEATURE_M)) {
-            target_cpu->env.event_register = true;
+            target_cpu->env.event_register.as_bool = true;
         }
         if (!qemu_cpu_is_self(cs)) {
             qemu_cpu_kick(cs);
@@ -503,8 +503,8 @@ void HELPER(wfe)(CPUARMState *env)
     if (arm_feature(env, ARM_FEATURE_M)) {
         CPUState *cs = env_cpu(env);
 
-        if (env->event_register) {
-            env->event_register = false;
+        if (env->event_register.as_bool) {
+            env->event_register.as_bool = false;
             return;
         }
 
-- 
2.47.3



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

* [RFC PATCH 28/35] target/arm: ensure aarch64 DISAS_WFE will exit
  2026-03-20 13:05 [RFC PATCH 00/35] target/arm: fully model WFxT instructions for A-profile Alex Bennée
                   ` (26 preceding siblings ...)
  2026-03-20 13:05 ` [RFC PATCH 27/35] target/arm: wrap event_register in a union Alex Bennée
@ 2026-03-20 13:05 ` Alex Bennée
  2026-04-06  3:00   ` Richard Henderson
  2026-03-20 13:06 ` [RFC PATCH 29/35] target/arm: implements SEV/SEVL for all modes Alex Bennée
                   ` (6 subsequent siblings)
  34 siblings, 1 reply; 74+ messages in thread
From: Alex Bennée @ 2026-03-20 13:05 UTC (permalink / raw)
  To: qemu-devel
  Cc: Alexander Graf, Peter Maydell, qemu-arm, Pedro Barbuda,
	Mohamed Mediouni, Alex Bennée

This mirrors the logic for DISAS_WFE in 32 bit world.

Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
---
 target/arm/tcg/translate-a64.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/target/arm/tcg/translate-a64.c b/target/arm/tcg/translate-a64.c
index 073454b9195..d79c8ab431b 100644
--- a/target/arm/tcg/translate-a64.c
+++ b/target/arm/tcg/translate-a64.c
@@ -10917,6 +10917,7 @@ static void aarch64_tr_tb_stop(DisasContextBase *dcbase, CPUState *cpu)
         case DISAS_WFE:
             gen_a64_update_pc(dc, 4);
             gen_helper_wfe(tcg_env);
+            tcg_gen_exit_tb(NULL, 0);
             break;
         case DISAS_YIELD:
             gen_a64_update_pc(dc, 4);
-- 
2.47.3



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

* [RFC PATCH 29/35] target/arm: implements SEV/SEVL for all modes
  2026-03-20 13:05 [RFC PATCH 00/35] target/arm: fully model WFxT instructions for A-profile Alex Bennée
                   ` (27 preceding siblings ...)
  2026-03-20 13:05 ` [RFC PATCH 28/35] target/arm: ensure aarch64 DISAS_WFE will exit Alex Bennée
@ 2026-03-20 13:06 ` Alex Bennée
  2026-04-06  3:22   ` Richard Henderson
  2026-03-20 13:06 ` [RFC PATCH 30/35] target/arm: implement global monitor events Alex Bennée
                   ` (5 subsequent siblings)
  34 siblings, 1 reply; 74+ messages in thread
From: Alex Bennée @ 2026-03-20 13:06 UTC (permalink / raw)
  To: qemu-devel
  Cc: Alexander Graf, Peter Maydell, qemu-arm, Pedro Barbuda,
	Mohamed Mediouni, Alex Bennée

Remove the restrictions that make this a M-profile only operation and
enable the instructions for all Arm instructions.

Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
---
 target/arm/tcg/a32.decode      |  5 ++---
 target/arm/tcg/a64.decode      |  5 ++---
 target/arm/tcg/t16.decode      |  4 +---
 target/arm/tcg/t32.decode      |  4 +---
 target/arm/tcg/op_helper.c     |  4 +---
 target/arm/tcg/translate-a64.c | 34 ++++++++++++++++++++++++++++++++++
 target/arm/tcg/translate.c     | 19 ++++++++++++++-----
 7 files changed, 55 insertions(+), 20 deletions(-)

diff --git a/target/arm/tcg/a32.decode b/target/arm/tcg/a32.decode
index f2ca4809495..d076681bf97 100644
--- a/target/arm/tcg/a32.decode
+++ b/target/arm/tcg/a32.decode
@@ -192,9 +192,8 @@ SMULTT           .... 0001 0110 .... 0000 .... 1110 ....      @rd0mn
       WFE        ---- 0011 0010 0000 1111 ---- 0000 0010
       WFI        ---- 0011 0010 0000 1111 ---- 0000 0011
 
-      # TODO: Implement SEV, SEVL; may help SMP performance.
-      # SEV      ---- 0011 0010 0000 1111 ---- 0000 0100
-      # SEVL     ---- 0011 0010 0000 1111 ---- 0000 0101
+      SEV      ---- 0011 0010 0000 1111 ---- 0000 0100
+      SEVL     ---- 0011 0010 0000 1111 ---- 0000 0101
 
       ESB        ---- 0011 0010 0000 1111 ---- 0001 0000
     ]
diff --git a/target/arm/tcg/a64.decode b/target/arm/tcg/a64.decode
index 01b1b3e38be..dcb3099dd5c 100644
--- a/target/arm/tcg/a64.decode
+++ b/target/arm/tcg/a64.decode
@@ -237,9 +237,8 @@ ERETA           1101011 0100 11111 00001 m:1 11111 11111 &reta  # ERETAA, ERETAB
     YIELD       1101 0101 0000 0011 0010 0000 001 11111
     WFE         1101 0101 0000 0011 0010 0000 010 11111
     WFI         1101 0101 0000 0011 0010 0000 011 11111
-    # We implement WFE to never block, so our SEV/SEVL are NOPs
-    # SEV       1101 0101 0000 0011 0010 0000 100 11111
-    # SEVL      1101 0101 0000 0011 0010 0000 101 11111
+    SEV         1101 0101 0000 0011 0010 0000 100 11111
+    SEVL        1101 0101 0000 0011 0010 0000 101 11111
     # Our DGL is a NOP because we don't merge memory accesses anyway.
     # DGL       1101 0101 0000 0011 0010 0000 110 11111
     XPACLRI     1101 0101 0000 0011 0010 0000 111 11111
diff --git a/target/arm/tcg/t16.decode b/target/arm/tcg/t16.decode
index 778fbf16275..9a8f89538ac 100644
--- a/target/arm/tcg/t16.decode
+++ b/target/arm/tcg/t16.decode
@@ -228,10 +228,8 @@ REVSH           1011 1010 11 ... ...            @rdm
     WFE         1011 1111 0010 0000
     WFI         1011 1111 0011 0000
 
-    # M-profile SEV is implemented.
-    # TODO: Implement SEV for other profiles, and SEVL for all profiles; may help SMP performance.
     SEV         1011 1111 0100 0000
-    # SEVL      1011 1111 0101 0000
+    SEVL        1011 1111 0101 0000
 
     # The canonical nop has the second nibble as 0000, but the whole of the
     # rest of the space is a reserved hint, behaves as nop.
diff --git a/target/arm/tcg/t32.decode b/target/arm/tcg/t32.decode
index 49b8d0037ec..8ae277fe112 100644
--- a/target/arm/tcg/t32.decode
+++ b/target/arm/tcg/t32.decode
@@ -369,10 +369,8 @@ CLZ              1111 1010 1011 ---- 1111 .... 1000 ....      @rdm
         WFE      1111 0011 1010 1111 1000 0000 0000 0010
         WFI      1111 0011 1010 1111 1000 0000 0000 0011
 
-        # M-profile SEV is implemented.
-        # TODO: Implement SEV for other profiles, and SEVL for all profiles; may help SMP performance.
         SEV      1111 0011 1010 1111 1000 0000 0000 0100
-        # SEVL   1111 0011 1010 1111 1000 0000 0000 0101
+        SEVL     1111 0011 1010 1111 1000 0000 0000 0101
 
         ESB      1111 0011 1010 1111 1000 0000 0001 0000
       ]
diff --git a/target/arm/tcg/op_helper.c b/target/arm/tcg/op_helper.c
index b5c8024ace7..d513045269c 100644
--- a/target/arm/tcg/op_helper.c
+++ b/target/arm/tcg/op_helper.c
@@ -475,9 +475,7 @@ void HELPER(sev)(CPUARMState *env)
     CPUState *cs = env_cpu(env);
     CPU_FOREACH(cs) {
         ARMCPU *target_cpu = ARM_CPU(cs);
-        if (arm_feature(&target_cpu->env, ARM_FEATURE_M)) {
-            target_cpu->env.event_register.as_bool = true;
-        }
+        target_cpu->env.event_register.as_bool = true;
         if (!qemu_cpu_is_self(cs)) {
             qemu_cpu_kick(cs);
         }
diff --git a/target/arm/tcg/translate-a64.c b/target/arm/tcg/translate-a64.c
index d79c8ab431b..c25ff9351b4 100644
--- a/target/arm/tcg/translate-a64.c
+++ b/target/arm/tcg/translate-a64.c
@@ -562,6 +562,23 @@ static void gen_goto_tb(DisasContext *s, unsigned tb_slot_idx, int64_t diff)
     }
 }
 
+/*
+ * Event Register signalling.
+ *
+ * A bunch of activities trigger events, we just need to latch on to
+ * true. The event eventually gets consumed by WFE/WFET.
+ *
+ * user-mode treats these as nops.
+ */
+
+static void gen_event_reg(void)
+{
+#ifndef CONFIG_USER_ONLY
+    TCGv_i32 set_event = tcg_constant_i32(-1);
+    tcg_gen_st_i32(set_event, tcg_env, offsetof(CPUARMState, event_register));
+#endif
+}
+
 /*
  * Register access functions
  *
@@ -2032,6 +2049,23 @@ static bool trans_WFI(DisasContext *s, arg_WFI *a)
     return true;
 }
 
+static bool trans_SEV(DisasContext *s, arg_SEV *a)
+{
+    /*
+     * SEV is a NOP for user-mode emulation.
+     */
+#ifndef CONFIG_USER_ONLY
+    gen_helper_sev(tcg_env);
+#endif
+    return true;
+}
+
+static bool trans_SEVL(DisasContext *s, arg_SEV *a)
+{
+    gen_event_reg();
+    return true;
+}
+
 static bool trans_WFE(DisasContext *s, arg_WFI *a)
 {
     /*
diff --git a/target/arm/tcg/translate.c b/target/arm/tcg/translate.c
index f9d1b8897d2..3707561af0d 100644
--- a/target/arm/tcg/translate.c
+++ b/target/arm/tcg/translate.c
@@ -3244,13 +3244,22 @@ static bool trans_YIELD(DisasContext *s, arg_YIELD *a)
 static bool trans_SEV(DisasContext *s, arg_SEV *a)
 {
     /*
-     * Currently SEV is a NOP for non-M-profile and in user-mode emulation.
-     * For system-mode M-profile, it sets the event register.
+     * SEV is a NOP for user-mode emulation.
      */
 #ifndef CONFIG_USER_ONLY
-    if (arm_dc_feature(s, ARM_FEATURE_M)) {
-        gen_helper_sev(tcg_env);
-    }
+    gen_helper_sev(tcg_env);
+#endif
+    return true;
+}
+
+static bool trans_SEVL(DisasContext *s, arg_SEV *a)
+{
+    /*
+     * SEVL is a NOP for user-mode emulation.
+     */
+#ifndef CONFIG_USER_ONLY
+    TCGv_i32 set_event = tcg_constant_i32(-1);
+    tcg_gen_st_i32(set_event, tcg_env, offsetof(CPUARMState, event_register));
 #endif
     return true;
 }
-- 
2.47.3



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

* [RFC PATCH 30/35] target/arm: implement global monitor events
  2026-03-20 13:05 [RFC PATCH 00/35] target/arm: fully model WFxT instructions for A-profile Alex Bennée
                   ` (28 preceding siblings ...)
  2026-03-20 13:06 ` [RFC PATCH 29/35] target/arm: implements SEV/SEVL for all modes Alex Bennée
@ 2026-03-20 13:06 ` Alex Bennée
  2026-04-10  9:16   ` Peter Maydell
  2026-03-20 13:06 ` [RFC PATCH 31/35] target/arm: enable event stream on WFE instructions Alex Bennée
                   ` (4 subsequent siblings)
  34 siblings, 1 reply; 74+ messages in thread
From: Alex Bennée @ 2026-03-20 13:06 UTC (permalink / raw)
  To: qemu-devel
  Cc: Alexander Graf, Peter Maydell, qemu-arm, Pedro Barbuda,
	Mohamed Mediouni, Alex Bennée

Moving from Exclusive to Open Access should generate event stream
events. Technically a non-exclusive store to any address range covered
by the global monitor should also trigger such an event but we can
only detect that after the event by seeing if memory doesn't match
cpu_exclusive_val when processing the eventual store exclusive.

The CLREX instruction has the same effect as do other operations
clearing the exclusive state (such as eret).

Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
---
 target/arm/internals.h         | 1 +
 target/arm/tcg/translate-a64.c | 8 ++++++++
 2 files changed, 9 insertions(+)

diff --git a/target/arm/internals.h b/target/arm/internals.h
index 2296ac9cfb6..2e59d58f3d0 100644
--- a/target/arm/internals.h
+++ b/target/arm/internals.h
@@ -690,6 +690,7 @@ void arm_handle_psci_call(ARMCPU *cpu);
 static inline void arm_clear_exclusive(CPUARMState *env)
 {
     env->exclusive_addr = -1;
+    env->event_register.as_bool = true;
 }
 
 /**
diff --git a/target/arm/tcg/translate-a64.c b/target/arm/tcg/translate-a64.c
index c25ff9351b4..38a51eb3600 100644
--- a/target/arm/tcg/translate-a64.c
+++ b/target/arm/tcg/translate-a64.c
@@ -2270,6 +2270,7 @@ static bool trans_CHKFEAT(DisasContext *s, arg_CHKFEAT *a)
 static bool trans_CLREX(DisasContext *s, arg_CLREX *a)
 {
     tcg_gen_movi_i64(cpu_exclusive_addr, -1);
+    gen_event_reg();
     return true;
 }
 
@@ -3336,6 +3337,13 @@ static void gen_store_exclusive(DisasContext *s, int rd, int rt, int rt2,
     TCGv_i64 tmp, clean_addr;
     MemOp memop;
 
+    /*
+     * All StoreExcl operations will transition the global monitor
+     * from Exclusive to Open Access and at that point generate an
+     * Event.
+     */
+    gen_event_reg();
+
     /*
      * FIXME: We are out of spec here.  We have recorded only the address
      * from load_exclusive, not the entire range, and we assume that the
-- 
2.47.3



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

* [RFC PATCH 31/35] target/arm: enable event stream on WFE instructions
  2026-03-20 13:05 [RFC PATCH 00/35] target/arm: fully model WFxT instructions for A-profile Alex Bennée
                   ` (29 preceding siblings ...)
  2026-03-20 13:06 ` [RFC PATCH 30/35] target/arm: implement global monitor events Alex Bennée
@ 2026-03-20 13:06 ` Alex Bennée
  2026-03-20 13:06 ` [RFC PATCH 32/35] target/arm: implement WFET Alex Bennée
                   ` (3 subsequent siblings)
  34 siblings, 0 replies; 74+ messages in thread
From: Alex Bennée @ 2026-03-20 13:06 UTC (permalink / raw)
  To: qemu-devel
  Cc: Alexander Graf, Peter Maydell, qemu-arm, Pedro Barbuda,
	Mohamed Mediouni, Alex Bennée

Now we can calculate when the next event stream event is we can re-use
the wfxt_timer and configure it to fire as we enter a WFE that is
going to sleep. Reverse the M-profile logic so we can enter a sleep
state in both profiles.

Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
---
 target/arm/cpu.h           |  2 ++
 target/arm/cpu.c           |  5 +++++
 target/arm/tcg/op_helper.c | 37 ++++++++++++++++++-------------------
 3 files changed, 25 insertions(+), 19 deletions(-)

diff --git a/target/arm/cpu.h b/target/arm/cpu.h
index 9c25b60ae83..6a7d92d73db 100644
--- a/target/arm/cpu.h
+++ b/target/arm/cpu.h
@@ -967,6 +967,8 @@ struct ArchCPU {
     QEMUTimer *pmu_timer;
     /* Timer used for WFxT timeouts */
     QEMUTimer *wfxt_timer;
+    /* Are we in a WFE */
+    bool waiting_for_event;
 
     /* GPIO outputs for generic timer */
     qemu_irq gt_timer_outputs[NUM_GTIMERS];
diff --git a/target/arm/cpu.c b/target/arm/cpu.c
index d51599dfdab..a0569f74cd5 100644
--- a/target/arm/cpu.c
+++ b/target/arm/cpu.c
@@ -780,6 +780,11 @@ static void arm_wfxt_timer_cb(void *opaque)
     ARMCPU *cpu = opaque;
     CPUState *cs = CPU(cpu);
 
+    if (cpu->waiting_for_event) {
+        CPUARMState *env = &cpu->env;
+        env->event_register.as_bool = true;
+    }
+
     /*
      * We expect the CPU to be halted; this will cause arm_cpu_is_work()
      * to return true (so we will come out of halt even with no other
diff --git a/target/arm/tcg/op_helper.c b/target/arm/tcg/op_helper.c
index d513045269c..fbe160ab70a 100644
--- a/target/arm/tcg/op_helper.c
+++ b/target/arm/tcg/op_helper.c
@@ -494,31 +494,30 @@ void HELPER(wfe)(CPUARMState *env)
 #else
     /*
      * WFE (Wait For Event) is a hint instruction.
-     * For Cortex-M (M-profile), we implement the strict architectural behavior:
+     *
      * 1. Check the Event Register (set by SEV or SEVONPEND).
      * 2. If set, clear it and continue (consume the event).
      */
-    if (arm_feature(env, ARM_FEATURE_M)) {
-        CPUState *cs = env_cpu(env);
+    CPUState *cs = env_cpu(env);
+    ARMCPU *cpu = ARM_CPU(cs);
 
-        if (env->event_register.as_bool) {
-            env->event_register.as_bool = false;
-            return;
-        }
+    if (env->event_register.as_bool) {
+        env->event_register.as_bool = false;
+        return;
+    }
 
-        cs->exception_index = EXCP_HLT;
-        cs->halted = 1;
-        cpu_loop_exit(cs);
-    } else {
-        /*
-         * For A-profile and others, we rely on the existing "yield" behavior.
-         * Don't actually halt the CPU, just yield back to top
-         * level loop. This is not going into a "low power state"
-         * (ie halting until some event occurs), so we never take
-         * a configurable trap to a different exception level
-         */
-        HELPER(yield)(env);
+    /* For A-profile we also can be woken by the event stream */
+    if (arm_feature(env, ARM_FEATURE_AARCH64) && cpu->wfxt_timer) {
+        int64_t next_event = gt_calc_next_event_stream(env);
+        if (next_event > 0) {
+            cpu->waiting_for_event = true;
+            timer_mod(cpu->wfxt_timer, next_event);
+        }
     }
+
+    cs->exception_index = EXCP_HLT;
+    cs->halted = 1;
+    cpu_loop_exit(cs);
 #endif
 }
 
-- 
2.47.3



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

* [RFC PATCH 32/35] target/arm: implement WFET
  2026-03-20 13:05 [RFC PATCH 00/35] target/arm: fully model WFxT instructions for A-profile Alex Bennée
                   ` (30 preceding siblings ...)
  2026-03-20 13:06 ` [RFC PATCH 31/35] target/arm: enable event stream on WFE instructions Alex Bennée
@ 2026-03-20 13:06 ` Alex Bennée
  2026-03-20 13:06 ` [RFC PATCH 33/35] tests/tcg: split stage 1 between devices and RAM Alex Bennée
                   ` (2 subsequent siblings)
  34 siblings, 0 replies; 74+ messages in thread
From: Alex Bennée @ 2026-03-20 13:06 UTC (permalink / raw)
  To: qemu-devel
  Cc: Alexander Graf, Peter Maydell, qemu-arm, Pedro Barbuda,
	Mohamed Mediouni, Alex Bennée

Now we have the event stream and SEV/SEVL implemented we can finally
enable WFET for Aarch64.

Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
---
 target/arm/tcg/helper-defs.h   |  1 +
 target/arm/tcg/op_helper.c     | 80 ++++++++++++++++++++++++++++++++++
 target/arm/tcg/translate-a64.c | 15 ++++---
 3 files changed, 89 insertions(+), 7 deletions(-)

diff --git a/target/arm/tcg/helper-defs.h b/target/arm/tcg/helper-defs.h
index a05f2258f29..31ffcbc6448 100644
--- a/target/arm/tcg/helper-defs.h
+++ b/target/arm/tcg/helper-defs.h
@@ -56,6 +56,7 @@ DEF_HELPER_1(setend, void, env)
 DEF_HELPER_2(wfi, void, env, i32)
 DEF_HELPER_1(wfe, void, env)
 DEF_HELPER_2(wfit, void, env, i32)
+DEF_HELPER_2(wfet, void, env, i32)
 DEF_HELPER_1(yield, void, env)
 DEF_HELPER_1(pre_hvc, void, env)
 DEF_HELPER_2(pre_smc, void, env, i32)
diff --git a/target/arm/tcg/op_helper.c b/target/arm/tcg/op_helper.c
index fbe160ab70a..8b917b344c9 100644
--- a/target/arm/tcg/op_helper.c
+++ b/target/arm/tcg/op_helper.c
@@ -521,6 +521,86 @@ void HELPER(wfe)(CPUARMState *env)
 #endif
 }
 
+void HELPER(wfet)(CPUARMState *env, uint32_t rd)
+{
+#ifdef CONFIG_USER_ONLY
+    /*
+     * As for WFIT make it NOP here, because trying to raise EXCP_HLT
+     * would trigger an abort.
+     */
+    return;
+#else
+    ARMCPU *cpu = env_archcpu(env);
+    CPUState *cs = env_cpu(env);
+    uint32_t excp;
+    int target_el = check_wfx_trap(env, false, &excp);
+    /* The WFET should time out when CNTVCT_EL0 >= the specified value. */
+    uint64_t cntval = gt_get_countervalue(env);
+    uint64_t timeout = env->xregs[rd];
+    /*
+     * We want the value that we would get if we read CNTVCT_EL0 from
+     * the current exception level, so the direct_access offset, not
+     * the indirect_access one. Compare the pseudocode LocalTimeoutEvent(),
+     * which calls VirtualCounterTimer().
+     */
+    uint64_t offset = gt_direct_access_timer_offset(env, GTIMER_VIRT);
+    uint64_t cntvct = cntval - offset;
+    uint64_t nexttick;
+    int64_t next_event;
+
+    /*
+     * As for WFE if the event register is already set we can consume
+     * the event and return immediately.
+     */
+    if (env->event_register.as_bool) {
+        env->event_register.as_bool = false;
+        return;
+    }
+
+
+    if (cpu_has_work(cs) || cntvct >= timeout) {
+        /*
+         * Don't bother to go into our "low power state" if
+         * we would just wake up immediately.
+         */
+        return;
+    }
+
+    /* We might sleep, so now we check to see if we should trap */
+    if (target_el) {
+        env->pc -= 4;
+        raise_exception(env, excp, syn_wfx(1, 0xe, rd, 1, 2, false), target_el);
+    }
+
+    /*
+     * Finally work out if the timeout or event stream will kick in
+     * earlier.
+     */
+    if (uadd64_overflow(timeout, offset, &nexttick)) {
+        nexttick = UINT64_MAX;
+    }
+    if (nexttick > INT64_MAX / gt_cntfrq_period_ns(cpu)) {
+        nexttick = INT64_MAX;
+    }
+
+    next_event = gt_calc_next_event_stream(env);
+    if (next_event > 0 && next_event < nexttick) {
+        cpu->waiting_for_event = true;
+        timer_mod(cpu->wfxt_timer, next_event);
+    } else {
+        if (nexttick == INT64_MAX) {
+            timer_mod_ns(cpu->wfxt_timer, INT64_MAX);
+        } else {
+            timer_mod(cpu->wfxt_timer, nexttick);
+        }
+    }
+
+    cs->exception_index = EXCP_HLT;
+    cs->halted = 1;
+    cpu_loop_exit(cs);
+#endif
+}
+
 void HELPER(yield)(CPUARMState *env)
 {
     CPUState *cs = env_cpu(env);
diff --git a/target/arm/tcg/translate-a64.c b/target/arm/tcg/translate-a64.c
index 38a51eb3600..f7d33ac2310 100644
--- a/target/arm/tcg/translate-a64.c
+++ b/target/arm/tcg/translate-a64.c
@@ -2110,14 +2110,15 @@ static bool trans_WFET(DisasContext *s, arg_WFET *a)
         return false;
     }
 
-    /*
-     * We rely here on our WFE implementation being a NOP, so we
-     * don't need to do anything different to handle the WFET timeout
-     * from what trans_WFE does.
-     */
-    if (!(tb_cflags(s->base.tb) & CF_PARALLEL)) {
-        s->base.is_jmp = DISAS_WFE;
+    if (s->ss_active) {
+        /* Act like a NOP under architectural singlestep */
+        return true;
     }
+
+    gen_a64_update_pc(s, 4);
+    gen_helper_wfet(tcg_env, tcg_constant_i32(a->rd));
+    /* Go back to the main loop to check for interrupts */
+    s->base.is_jmp = DISAS_EXIT;
     return true;
 }
 
-- 
2.47.3



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

* [RFC PATCH 33/35] tests/tcg: split stage 1 between devices and RAM
  2026-03-20 13:05 [RFC PATCH 00/35] target/arm: fully model WFxT instructions for A-profile Alex Bennée
                   ` (31 preceding siblings ...)
  2026-03-20 13:06 ` [RFC PATCH 32/35] target/arm: implement WFET Alex Bennée
@ 2026-03-20 13:06 ` Alex Bennée
  2026-03-20 13:06 ` [RFC PATCH 34/35] tests/tcg: create a mini-gic3 library Alex Bennée
  2026-03-20 13:06 ` [RFC PATCH 35/35] tests/tcg: add basic test for aarch64 wf[ie][t] insns Alex Bennée
  34 siblings, 0 replies; 74+ messages in thread
From: Alex Bennée @ 2026-03-20 13:06 UTC (permalink / raw)
  To: qemu-devel
  Cc: Alexander Graf, Peter Maydell, qemu-arm, Pedro Barbuda,
	Mohamed Mediouni, Alex Bennée

All the -M virt devices live in the first GB of address space. Add a
1Gb block mapping for devices and continue pointing the second block
at stage 2 and adjust appropriately.

Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
---
 tests/tcg/aarch64/system/boot.S | 43 ++++++++++++++++++++-------------
 1 file changed, 26 insertions(+), 17 deletions(-)

diff --git a/tests/tcg/aarch64/system/boot.S b/tests/tcg/aarch64/system/boot.S
index 8bfa4e4efc7..03a5bad2ab0 100644
--- a/tests/tcg/aarch64/system/boot.S
+++ b/tests/tcg/aarch64/system/boot.S
@@ -248,29 +248,34 @@ at_testel:
 	msr	ttbr0_el1, x0
 
 	/*
-	 * Setup a flat address mapping page-tables. Stage one simply
-	 * maps RAM to the first Gb. The stage2 tables have two 2mb
-	 * translation block entries covering a series of adjacent
-	 * 4k pages.
+	 * Setup a flat address mapping page-tables.
+	 *
+	 * ttb (Level 1):
+	 *   - Entry 0 [0 - 1GB]: 1GB Device block (for GIC and other H/W)
+	 *   - Entry 1 [1GB - 2GB]: Table entry pointing to ttb_stage2 (for RAM)
 	 */
 
-	/* Stage 1 entry: indexed by IA[38:30] */
-	adr	x1, .				/* phys address */
-	bic	x1, x1, #(1 << 30) - 1		/* 1GB alignment*/
-	add	x2, x0, x1, lsr #(30 - 3)	/* offset in l1 page table */
+	/* Entry 0: 1GB Device block mapping at 0x0 */
+	ldr	x1, =0x401 | (1 << 2)		/* AF=1, block, AttrIndx=Attr1 (Device) */
+	str	x1, [x0]
 
-	/* point to stage 2 table [47:12] */
-	adrp	x0, ttb_stage2
-	orr 	x1, x0, #3 			/* ptr to stage 2 */
-	str	x1, [x2]
+	/* Entry 1: Table entry pointing to ttb_stage2 */
+	adrp	x1, ttb_stage2
+	orr 	x1, x1, #3 			/* ptr to table (type=3) */
+	str	x1, [x0, #8]
 
-	/* Stage 2 entries: indexed by IA[29:21] */
+	/* Stage 2 entries: indexed by IA[29:21] (within 1GB-2GB range) */
+	adrp	x0, ttb_stage2
+	add	x0, x0, :lo12:ttb_stage2
 	ldr	x5, =(((1 << 9) - 1) << 21)
 
 	/* First block: .text/RO/execute enabled */
 	adr	x1, .				/* phys address */
 	bic	x1, x1, #(1 << 21) - 1		/* 2mb block alignment	*/
-	and	x4, x1, x5			/* IA[29:21] */
+	/* Note: we assume RAM is in the 1GB-2GB range, so IA[30] is 1 */
+	mov	x4, x1
+	bic	x4, x4, #(1 << 30)		/* remove 1GB offset for L2 index */
+	and	x4, x4, x5			/* IA[29:21] */
 	add	x2, x0, x4, lsr #(21 - 3)	/* offset in l2 page table */
 	ldr	x3, =0x401			/* attr(AF, block) */
 	orr	x1, x1, x3
@@ -280,7 +285,9 @@ at_testel:
 	adrp	x1, .data
 	add	x1, x1, :lo12:.data
 	bic	x1, x1, #(1 << 21) - 1		/* 2mb block alignment */
-	and	x4, x1, x5			/* IA[29:21] */
+	mov	x4, x1
+	bic	x4, x4, #(1 << 30)		/* remove 1GB offset for L2 index */
+	and	x4, x4, x5			/* IA[29:21] */
 	add	x2, x0, x4, lsr #(21 - 3)	/* offset in l2 page table */
 	ldr	x3, =(3 << 53) | 0x401		/* attr(AF, NX, block) */
 	orr	x1, x1, x3
@@ -290,7 +297,9 @@ at_testel:
 	adrp	x1, mte_page
 	add	x1, x1, :lo12:mte_page
 	bic	x1, x1, #(1 << 21) - 1
-	and 	x4, x1, x5
+	mov	x4, x1
+	bic	x4, x4, #(1 << 30)		/* remove 1GB offset for L2 index */
+	and 	x4, x4, x5
 	add	x2, x0, x4, lsr #(21 - 3)
 	/* attr(AF, NX, block, AttrIndx=Attr1) */
 	ldr	x3, =(3 << 53) | 0x401 | (1 << 2)
@@ -317,7 +326,7 @@ at_testel:
 	ldr	x0, = (2 << 32) | 25 | (3 << 10) | (3 << 8)
 	msr	tcr_el1, x0
 
-	mov	x0, #0xee			/* Inner/outer cacheable WB */
+	ldr	x0, =0x04ee			/* Attr1: Device-nGnRE, Attr0: Normal WB */
 	msr	mair_el1, x0
 	isb
 
-- 
2.47.3



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

* [RFC PATCH 34/35] tests/tcg: create a mini-gic3 library
  2026-03-20 13:05 [RFC PATCH 00/35] target/arm: fully model WFxT instructions for A-profile Alex Bennée
                   ` (32 preceding siblings ...)
  2026-03-20 13:06 ` [RFC PATCH 33/35] tests/tcg: split stage 1 between devices and RAM Alex Bennée
@ 2026-03-20 13:06 ` Alex Bennée
  2026-03-20 13:06 ` [RFC PATCH 35/35] tests/tcg: add basic test for aarch64 wf[ie][t] insns Alex Bennée
  34 siblings, 0 replies; 74+ messages in thread
From: Alex Bennée @ 2026-03-20 13:06 UTC (permalink / raw)
  To: qemu-devel
  Cc: Alexander Graf, Peter Maydell, qemu-arm, Pedro Barbuda,
	Mohamed Mediouni, Alex Bennée

Just enough GIC to trigger timer interrupts.

Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
---
 tests/tcg/aarch64/system/lib/gicv3.h      | 56 +++++++++++++++++
 tests/tcg/aarch64/system/lib/gicv3.c      | 77 +++++++++++++++++++++++
 tests/tcg/aarch64/Makefile.softmmu-target |  7 ++-
 3 files changed, 138 insertions(+), 2 deletions(-)
 create mode 100644 tests/tcg/aarch64/system/lib/gicv3.h
 create mode 100644 tests/tcg/aarch64/system/lib/gicv3.c

diff --git a/tests/tcg/aarch64/system/lib/gicv3.h b/tests/tcg/aarch64/system/lib/gicv3.h
new file mode 100644
index 00000000000..9a1268937c6
--- /dev/null
+++ b/tests/tcg/aarch64/system/lib/gicv3.h
@@ -0,0 +1,56 @@
+/*
+ * GICv3 Helper Library
+ *
+ * Copyright (c) 2024 Linaro Ltd
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#ifndef GICV3_H
+#define GICV3_H
+
+#include <stdint.h>
+
+/* Virt machine GICv3 base addresses */
+#define GICD_BASE       0x08000000  /* c.f. VIRT_GIC_DIST */
+#define GICR_BASE       0x080a0000  /* c.f. VIRT_GIC_REDIST */
+
+/* Distributor registers */
+#define GICD_CTLR       (GICD_BASE + 0x0000)
+#define GICD_TYPER      (GICD_BASE + 0x0004)
+#define GICD_IIDR       (GICD_BASE + 0x0008)
+
+/* Redistributor registers (per-CPU) */
+#define GICR_SGI_OFFSET 0x00010000
+
+#define GICR_CTLR       0x0000
+#define GICR_WAKER      0x0014
+#define GICR_IGROUPR0   (GICR_SGI_OFFSET + 0x0080)
+#define GICR_ISENABLER0 (GICR_SGI_OFFSET + 0x0100)
+#define GICR_IPRIORITYR0 (GICR_SGI_OFFSET + 0x0400)
+
+/* GICD_CTLR bits */
+#define GICD_CTLR_ARE_NS (1U << 4)
+#define GICD_CTLR_ENA_G1NS (1U << 1)
+#define GICD_CTLR_ENA_G0 (1U << 0)
+
+/* GICR_WAKER bits */
+#define GICR_WAKER_ChildrenAsleep (1U << 2)
+#define GICR_WAKER_ProcessorSleep (1U << 1)
+
+/**
+ * gicv3_init:
+ *
+ * Initialize GICv3 distributor and the redistributor for the current CPU.
+ */
+void gicv3_init(void);
+
+/**
+ * gicv3_enable_irq:
+ * @irq: The IRQ number to enable
+ *
+ * Enable the specified IRQ (SPI or PPI).
+ */
+void gicv3_enable_irq(unsigned int irq);
+
+#endif /* GICV3_H */
diff --git a/tests/tcg/aarch64/system/lib/gicv3.c b/tests/tcg/aarch64/system/lib/gicv3.c
new file mode 100644
index 00000000000..a09a0e430e6
--- /dev/null
+++ b/tests/tcg/aarch64/system/lib/gicv3.c
@@ -0,0 +1,77 @@
+/*
+ * GICv3 Helper Library Implementation
+ *
+ * Copyright (c) 2024 Linaro Ltd
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "gicv3.h"
+
+#define write_sysreg(r, v) do {                     \
+        uint64_t __val = (uint64_t)(v);             \
+        asm volatile("msr " #r ", %x0"              \
+                 : : "rZ" (__val));                 \
+} while (0)
+
+#define isb() asm volatile("isb" : : : "memory")
+
+static inline void write_reg(uintptr_t addr, uint32_t val)
+{
+    *(volatile uint32_t *)addr = val;
+}
+
+static inline uint32_t read_reg(uintptr_t addr)
+{
+    return *(volatile uint32_t *)addr;
+}
+
+void gicv3_init(void)
+{
+    uint32_t val;
+
+    /* 1. Enable Distributor ARE and Group 1 NS */
+    val = read_reg(GICD_CTLR);
+    val |= GICD_CTLR_ARE_NS | GICD_CTLR_ENA_G1NS;
+    write_reg(GICD_CTLR, val);
+
+    /* 2. Wake up Redistributor 0 */
+    /* Clear ProcessorSleep */
+    val = read_reg(GICR_BASE + GICR_WAKER);
+    val &= ~GICR_WAKER_ProcessorSleep;
+    write_reg(GICR_BASE + GICR_WAKER, val);
+
+    /* Wait for ChildrenAsleep to be cleared */
+    while (read_reg(GICR_BASE + GICR_WAKER) & GICR_WAKER_ChildrenAsleep) {
+        /* spin */
+    }
+
+    /* 3. Enable CPU interface */
+    /* Set Priority Mask to allow all interrupts */
+    write_sysreg(ICC_PMR_EL1, 0xff);
+    /* Enable Group 1 Non-Secure interrupts */
+    write_sysreg(ICC_IGRPEN1_EL1, 1);
+    isb();
+}
+
+void gicv3_enable_irq(unsigned int irq)
+{
+    if (irq < 32) {
+        /* PPI: use GICR_ISENABLER0 */
+        uintptr_t addr;
+
+        /* Set Group 1 */
+        addr = GICR_BASE + GICR_IGROUPR0;
+        write_reg(addr, read_reg(addr) | (1U << irq));
+
+        /* Set priority (0xa0) */
+        addr = GICR_BASE + GICR_IPRIORITYR0 + irq;
+        *(volatile uint8_t *)addr = 0xa0;
+
+        /* Enable it */
+        addr = GICR_BASE + GICR_ISENABLER0;
+        write_reg(addr, 1U << irq);
+    } else {
+        /* SPI: not implemented yet */
+    }
+}
diff --git a/tests/tcg/aarch64/Makefile.softmmu-target b/tests/tcg/aarch64/Makefile.softmmu-target
index f7a7d2b800f..c0939a0eeca 100644
--- a/tests/tcg/aarch64/Makefile.softmmu-target
+++ b/tests/tcg/aarch64/Makefile.softmmu-target
@@ -4,8 +4,9 @@
 
 AARCH64_SRC=$(SRC_PATH)/tests/tcg/aarch64
 AARCH64_SYSTEM_SRC=$(AARCH64_SRC)/system
+AARCH64_SYSTEM_LIB_SRC=$(AARCH64_SYSTEM_SRC)/lib
 
-VPATH+=$(AARCH64_SYSTEM_SRC)
+VPATH+=$(AARCH64_SYSTEM_SRC) $(AARCH64_SYSTEM_LIB_SRC)
 
 # These objects provide the basic boot code and helper functions for all tests
 CRT_OBJS=boot.o
@@ -24,7 +25,7 @@ LINK_SCRIPT=$(AARCH64_SYSTEM_SRC)/kernel.ld
 LDFLAGS=-Wl,-T$(LINK_SCRIPT)
 TESTS+=$(AARCH64_TESTS) $(MULTIARCH_TESTS)
 EXTRA_RUNS+=$(MULTIARCH_RUNS)
-CFLAGS+=-nostdlib -ggdb -O0 $(MINILIB_INC)
+CFLAGS+=-nostdlib -ggdb -O0 $(MINILIB_INC) -I$(AARCH64_SYSTEM_LIB_SRC)
 LDFLAGS+=-static -nostdlib $(CRT_OBJS) $(MINILIB_OBJS) -lgcc
 
 config-cc.mak: Makefile
@@ -102,6 +103,8 @@ run-pauth-3:
 	$(call skip-test, "RUN of pauth-3", "not built")
 endif
 
+gicv3.o: gicv3.c gicv3.h
+	$(CC) $(CFLAGS) $(EXTRA_CFLAGS) -c $< -o $@
 ifneq ($(CROSS_CC_HAS_ARMV8_MTE),)
 QEMU_MTE_ENABLED_MACHINE=-M virt,mte=on -cpu max -display none
 QEMU_OPTS_WITH_MTE_ON = $(QEMU_MTE_ENABLED_MACHINE) $(QEMU_BASE_ARGS) -kernel
-- 
2.47.3



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

* [RFC PATCH 35/35] tests/tcg: add basic test for aarch64 wf[ie][t] insns
  2026-03-20 13:05 [RFC PATCH 00/35] target/arm: fully model WFxT instructions for A-profile Alex Bennée
                   ` (33 preceding siblings ...)
  2026-03-20 13:06 ` [RFC PATCH 34/35] tests/tcg: create a mini-gic3 library Alex Bennée
@ 2026-03-20 13:06 ` Alex Bennée
  34 siblings, 0 replies; 74+ messages in thread
From: Alex Bennée @ 2026-03-20 13:06 UTC (permalink / raw)
  To: qemu-devel
  Cc: Alexander Graf, Peter Maydell, qemu-arm, Pedro Barbuda,
	Mohamed Mediouni, Alex Bennée

Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
---
 tests/tcg/aarch64/system/wfx.c            | 126 ++++++++++++++++++++++
 tests/tcg/aarch64/Makefile.softmmu-target |   8 ++
 tests/tcg/aarch64/system/boot.S           |  12 ++-
 3 files changed, 145 insertions(+), 1 deletion(-)
 create mode 100644 tests/tcg/aarch64/system/wfx.c

diff --git a/tests/tcg/aarch64/system/wfx.c b/tests/tcg/aarch64/system/wfx.c
new file mode 100644
index 00000000000..567d9e59c70
--- /dev/null
+++ b/tests/tcg/aarch64/system/wfx.c
@@ -0,0 +1,126 @@
+/*
+ * WFX Instructions Test (WFI, WFE, WFIT, WFET)
+ *
+ * Copyright (c) 2024 Linaro Ltd
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include <stdint.h>
+#include <minilib.h>
+#include "gicv3.h"
+
+#define __stringify_1(x...) #x
+#define __stringify(x...)   __stringify_1(x)
+
+#define read_sysreg(r) ({                                           \
+            uint64_t __val;                                         \
+            asm volatile("mrs %0, " __stringify(r) : "=r" (__val)); \
+            __val;                                                  \
+})
+
+#define write_sysreg(r, v) do {                     \
+        uint64_t __val = (uint64_t)(v);             \
+        asm volatile("msr " __stringify(r) ", %x0"  \
+                 : : "rZ" (__val));                 \
+} while (0)
+
+#define isb() asm volatile("isb" : : : "memory")
+#define sev() asm volatile("sev" : : : "memory")
+#define wfi() asm volatile("wfi" : : : "memory")
+#define wfe() asm volatile("wfe" : : : "memory")
+#define wfit(reg) asm volatile("wfit %0" : : "r" (reg) : "memory")
+#define wfet(reg) asm volatile("wfet %0" : : "r" (reg) : "memory")
+
+#define enable_irq()  asm volatile("msr daifclr, #2" : : : "memory")
+#define disable_irq() asm volatile("msr daifset, #2" : : : "memory")
+
+static void wait_ticks(uint64_t ticks)
+{
+    uint64_t start = read_sysreg(cntvct_el0);
+    while ((read_sysreg(cntvct_el0) - start) < ticks) {
+        /* spin */
+    }
+}
+
+int main(void)
+{
+    uint64_t start, end, elapsed;
+    uint64_t timeout;
+
+    gicv3_init();
+    gicv3_enable_irq(27); /* Virtual Timer PPI */
+
+    ml_printf("WFX Test\n");
+
+    /* 1. Test WFI with timer interrupt */
+    ml_printf("Testing WFI...");
+    /* Setup virtual timer to fire in 100000 ticks (~2ms at 50MHz) */
+    start = read_sysreg(cntvct_el0);
+    write_sysreg(cntv_tval_el0, 100000);
+    write_sysreg(cntv_ctl_el0, 1); /* Enable timer, no mask */
+    isb();
+
+    /*
+     * We don't have a full interrupt handler, but WFI should wake up
+     * when the interrupt is pending even if we have it masked at the CPU.
+     * PSTATE.I is set by boot code.
+     *
+     * We unmask interrupts here to ensure the CPU can take the minimal
+     * exception handler defined in boot.S.
+     */
+    enable_irq();
+    wfi();
+    disable_irq();
+    end = read_sysreg(cntvct_el0);
+    elapsed = end - start;
+    if (elapsed < 100000) {
+        ml_printf("FAILED: WFI woke too early (%ld ticks)\n", elapsed);
+        return 1;
+    }
+    ml_printf("PASSED (elapsed %ld ticks)\n", elapsed);
+    write_sysreg(cntv_ctl_el0, 0); /* Disable timer */
+
+    /* 2. Test WFE and SEV */
+    ml_printf("Testing WFE/SEV...");
+    sev(); /* Set event register */
+    start = read_sysreg(cntvct_el0);
+    wfe(); /* Should return immediately */
+    end = read_sysreg(cntvct_el0);
+    elapsed = end - start;
+    /* while this should be fast there is some overhead from TCG */
+    if (elapsed > 20000) {
+        ml_printf("FAILED: WFE slept despite SEV (%ld ticks)\n", elapsed);
+        return 1;
+    }
+    ml_printf("PASSED (%ld ticks)\n", elapsed);
+
+    /* 3. Test WFIT */
+    ml_printf("Testing WFIT...");
+    start = read_sysreg(cntvct_el0);
+    timeout = start + 200000;
+    wfit(timeout);
+    end = read_sysreg(cntvct_el0);
+    elapsed = end - start;
+    if (elapsed < 200000) {
+        ml_printf("FAILED: WFIT woke too early (%ld ticks)\n", elapsed);
+        return 1;
+    }
+    ml_printf("PASSED (elapsed %ld ticks)\n", elapsed);
+
+    /* 4. Test WFET */
+    ml_printf("Testing WFET...");
+    start = read_sysreg(cntvct_el0);
+    timeout = start + 200000;
+    wfet(timeout);
+    end = read_sysreg(cntvct_el0);
+    elapsed = end - start;
+    if (elapsed < 200000) {
+        ml_printf("FAILED: WFET woke too early (%ld ticks)\n", elapsed);
+        return 1;
+    }
+    ml_printf("PASSED (elapsed %ld ticks)\n", elapsed);
+
+    ml_printf("ALL WFX TESTS PASSED\n");
+    return 0;
+}
diff --git a/tests/tcg/aarch64/Makefile.softmmu-target b/tests/tcg/aarch64/Makefile.softmmu-target
index c0939a0eeca..9a5b95de621 100644
--- a/tests/tcg/aarch64/Makefile.softmmu-target
+++ b/tests/tcg/aarch64/Makefile.softmmu-target
@@ -105,6 +105,14 @@ endif
 
 gicv3.o: gicv3.c gicv3.h
 	$(CC) $(CFLAGS) $(EXTRA_CFLAGS) -c $< -o $@
+
+wfx: CFLAGS += -march=armv8.7-a
+wfx: LDFLAGS += gicv3.o
+wfx: gicv3.o
+
+QEMU_GICV3_MACHINE=-M virt,gic-version=3 -cpu max -display none
+run-wfx: QEMU_OPTS=$(QEMU_GICV3_MACHINE) $(QEMU_BASE_ARGS) -kernel
+
 ifneq ($(CROSS_CC_HAS_ARMV8_MTE),)
 QEMU_MTE_ENABLED_MACHINE=-M virt,mte=on -cpu max -display none
 QEMU_OPTS_WITH_MTE_ON = $(QEMU_MTE_ENABLED_MACHINE) $(QEMU_BASE_ARGS) -kernel
diff --git a/tests/tcg/aarch64/system/boot.S b/tests/tcg/aarch64/system/boot.S
index 03a5bad2ab0..6a71fc0da5a 100644
--- a/tests/tcg/aarch64/system/boot.S
+++ b/tests/tcg/aarch64/system/boot.S
@@ -60,7 +60,6 @@ curr_sp0_irq:
 curr_sp0_fiq:
 curr_sp0_serror:
 curr_spx_sync:
-curr_spx_irq:
 curr_spx_fiq:
 curr_spx_serror:
 lower_a64_sync:
@@ -379,6 +378,17 @@ _exit:
 	semihosting_call
 	/* never returns */
 
+	/*
+	 * IRQ handler
+	 */
+	.global curr_spx_irq
+curr_spx_irq:
+	/* Minimal IRQ handler: just mask the timer and return */
+	mrs	x0, cntv_ctl_el0
+	orr	x0, x0, #2		/* IMASK=1 */
+	msr	cntv_ctl_el0, x0
+	eret
+
 	/*
 	 * Helper Functions
 	*/
-- 
2.47.3



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

* Re: [RFC PATCH 01/35] target/arm: migrate basic syndrome helpers to registerfields
  2026-03-20 13:05 ` [RFC PATCH 01/35] target/arm: migrate basic syndrome helpers to registerfields Alex Bennée
@ 2026-04-01  5:36   ` Richard Henderson
  0 siblings, 0 replies; 74+ messages in thread
From: Richard Henderson @ 2026-04-01  5:36 UTC (permalink / raw)
  To: qemu-devel

On 3/20/26 23:05, Alex Bennée wrote:
> We have a registerfields interface which we can use for defining
> fields alongside helpers to access them. Define the basic syndrome
> layout and convert the helpers that take the imm16 data directly.
> 
> Signed-off-by: Alex Bennée<alex.bennee@linaro.org>
> ---
>   target/arm/syndrome.h | 75 ++++++++++++++++++++++++++++++++-----------
>   1 file changed, 57 insertions(+), 18 deletions(-)

Reviewed-by: Richard Henderson <richard.henderson@linaro.org>

r~


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

* Re: [RFC PATCH 02/35] target/arm: migrate system/cp trap syndromes to registerfields
  2026-03-20 13:05 ` [RFC PATCH 02/35] target/arm: migrate system/cp trap syndromes " Alex Bennée
@ 2026-04-01  5:39   ` Richard Henderson
  0 siblings, 0 replies; 74+ messages in thread
From: Richard Henderson @ 2026-04-01  5:39 UTC (permalink / raw)
  To: Alex Bennée, qemu-devel
  Cc: Alexander Graf, Peter Maydell, qemu-arm, Pedro Barbuda,
	Mohamed Mediouni

On 3/20/26 23:05, Alex Bennée wrote:
>   static inline uint32_t syn_cp14_rt_trap(int cv, int cond, int opc1, int opc2,
>                                           int crn, int crm, int rt, int isread,
>                                           bool is_16bit)
>   {
> -    return (EC_CP14RTTRAP << ARM_EL_EC_SHIFT)
> -        | (is_16bit ? 0 : ARM_EL_IL)
> -        | (cv << 24) | (cond << 20) | (opc2 << 17) | (opc1 << 14)
> -        | (crn << 10) | (rt << 5) | (crm << 1) | isread;
> +    uint32_t res = syn_set_ec(0, EC_CP14RTTRAP);
> +    res = FIELD_DP32(res, SYNDROME, IL, is_16bit ? 0 : 1);

!is_16bit.

> +    res = FIELD_DP32(res, SYNDROME, IL, is_16bit ? 0 : 1);
...
> +    res = FIELD_DP32(res, SYNDROME, IL, is_16bit ? 0 : 1);
...
> +    res = FIELD_DP32(res, SYNDROME, IL, is_16bit ? 0 : 1);

Likewise.

Otherwise,
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>


r~


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

* Re: [RFC PATCH 03/35] target/arm: migrate FP/SIMD trap syndromes to registerfields
  2026-03-20 13:05 ` [RFC PATCH 03/35] target/arm: migrate FP/SIMD " Alex Bennée
@ 2026-04-01  5:43   ` Richard Henderson
  2026-04-01 12:50     ` Alex Bennée
  0 siblings, 1 reply; 74+ messages in thread
From: Richard Henderson @ 2026-04-01  5:43 UTC (permalink / raw)
  To: qemu-devel

On 3/20/26 23:05, Alex Bennée wrote:
>   static inline uint32_t syn_fp_access_trap(int cv, int cond, bool is_16bit,
>                                             int coproc)
>   {
>       /* AArch32 FP trap or any AArch64 FP/SIMD trap: TA == 0 */
> -    return (EC_ADVSIMDFPACCESSTRAP << ARM_EL_EC_SHIFT)
> -        | (is_16bit ? 0 : ARM_EL_IL)
> -        | (cv << 24) | (cond << 20) | coproc;
> -}
> +    uint32_t res = syn_set_ec(0, EC_ADVSIMDFPACCESSTRAP);
> +    res = FIELD_DP32(res, SYNDROME, IL, is_16bit ? 0 : 1);

!is_16bit.  I'll not mention it again in the series, but take as given.

Reviewed-by: Richard Henderson <richard.henderson@linaro.org>

r~


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

* Re: [RFC PATCH 03/35] target/arm: migrate FP/SIMD trap syndromes to registerfields
  2026-04-01  5:43   ` Richard Henderson
@ 2026-04-01 12:50     ` Alex Bennée
  2026-04-01 15:48       ` Peter Maydell
  2026-04-01 17:54       ` Pierrick Bouvier
  0 siblings, 2 replies; 74+ messages in thread
From: Alex Bennée @ 2026-04-01 12:50 UTC (permalink / raw)
  To: Richard Henderson; +Cc: qemu-devel

Richard Henderson <richard.henderson@linaro.org> writes:

> On 3/20/26 23:05, Alex Bennée wrote:
>>   static inline uint32_t syn_fp_access_trap(int cv, int cond, bool is_16bit,
>>                                             int coproc)
>>   {
>>       /* AArch32 FP trap or any AArch64 FP/SIMD trap: TA == 0 */
>> -    return (EC_ADVSIMDFPACCESSTRAP << ARM_EL_EC_SHIFT)
>> -        | (is_16bit ? 0 : ARM_EL_IL)
>> -        | (cv << 24) | (cond << 20) | coproc;
>> -}
>> +    uint32_t res = syn_set_ec(0, EC_ADVSIMDFPACCESSTRAP);
>> +    res = FIELD_DP32(res, SYNDROME, IL, is_16bit ? 0 : 1);
>
> !is_16bit.  I'll not mention it again in the series, but take as
> given.

Impressive that I managed to run all our tests and nothing tripped up on
this!

>
> Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
>
> r~

-- 
Alex Bennée
Virtualisation Tech Lead @ Linaro


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

* Re: [RFC PATCH 03/35] target/arm: migrate FP/SIMD trap syndromes to registerfields
  2026-04-01 12:50     ` Alex Bennée
@ 2026-04-01 15:48       ` Peter Maydell
  2026-04-01 17:54       ` Pierrick Bouvier
  1 sibling, 0 replies; 74+ messages in thread
From: Peter Maydell @ 2026-04-01 15:48 UTC (permalink / raw)
  To: Alex Bennée; +Cc: Richard Henderson, qemu-devel

On Wed, 1 Apr 2026 at 13:51, Alex Bennée <alex.bennee@linaro.org> wrote:
>
> Richard Henderson <richard.henderson@linaro.org> writes:
>
> > On 3/20/26 23:05, Alex Bennée wrote:
> >>   static inline uint32_t syn_fp_access_trap(int cv, int cond, bool is_16bit,
> >>                                             int coproc)
> >>   {
> >>       /* AArch32 FP trap or any AArch64 FP/SIMD trap: TA == 0 */
> >> -    return (EC_ADVSIMDFPACCESSTRAP << ARM_EL_EC_SHIFT)
> >> -        | (is_16bit ? 0 : ARM_EL_IL)
> >> -        | (cv << 24) | (cond << 20) | coproc;
> >> -}
> >> +    uint32_t res = syn_set_ec(0, EC_ADVSIMDFPACCESSTRAP);
> >> +    res = FIELD_DP32(res, SYNDROME, IL, is_16bit ? 0 : 1);
> >
> > !is_16bit.  I'll not mention it again in the series, but take as
> > given.
>
> Impressive that I managed to run all our tests and nothing tripped up on
> this!

"!is_16bit" and "is_16bit ? 0 : 1" evaluate to the same thing...

-- PMM


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

* Re: [RFC PATCH 03/35] target/arm: migrate FP/SIMD trap syndromes to registerfields
  2026-04-01 12:50     ` Alex Bennée
  2026-04-01 15:48       ` Peter Maydell
@ 2026-04-01 17:54       ` Pierrick Bouvier
  1 sibling, 0 replies; 74+ messages in thread
From: Pierrick Bouvier @ 2026-04-01 17:54 UTC (permalink / raw)
  To: Alex Bennée, Richard Henderson; +Cc: qemu-devel

On 4/1/26 5:50 AM, Alex Bennée wrote:
> Richard Henderson <richard.henderson@linaro.org> writes:
> 
>> On 3/20/26 23:05, Alex Bennée wrote:
>>>    static inline uint32_t syn_fp_access_trap(int cv, int cond, bool is_16bit,
>>>                                              int coproc)
>>>    {
>>>        /* AArch32 FP trap or any AArch64 FP/SIMD trap: TA == 0 */
>>> -    return (EC_ADVSIMDFPACCESSTRAP << ARM_EL_EC_SHIFT)
>>> -        | (is_16bit ? 0 : ARM_EL_IL)
>>> -        | (cv << 24) | (cond << 20) | coproc;
>>> -}
>>> +    uint32_t res = syn_set_ec(0, EC_ADVSIMDFPACCESSTRAP);
>>> +    res = FIELD_DP32(res, SYNDROME, IL, is_16bit ? 0 : 1);
>>
>> !is_16bit.  I'll not mention it again in the series, but take as
>> given.
> 
> Impressive that I managed to run all our tests and nothing tripped up on
> this!
>

Try running all tests (check-tcg + check thorough) on instrumented gprof 
qemu-system-ar* binaries, you'll be surprised to see what is actually 
covered by our full test suite.

Note: It's probably less than what you expect.

>>
>> Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
>>
>> r~
> 


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

* Re: [RFC PATCH 04/35] target/arm: migrate eret trap syndromes to registerfields
  2026-03-20 13:05 ` [RFC PATCH 04/35] target/arm: migrate eret " Alex Bennée
@ 2026-04-05 23:21   ` Richard Henderson
  0 siblings, 0 replies; 74+ messages in thread
From: Richard Henderson @ 2026-04-05 23:21 UTC (permalink / raw)
  To: qemu-devel

On 3/21/26 00:05, Alex Bennée wrote:
> For simplicity keep the OP as a two bit field rather than the two
> interlinked fields in the docs (ERET/ERETA).
> 
> Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
> ---
>   target/arm/syndrome.h | 11 ++++++++++-
>   1 file changed, 10 insertions(+), 1 deletion(-)
> 
> diff --git a/target/arm/syndrome.h b/target/arm/syndrome.h
> index 5b5a5cb182e..b145a52769f 100644
> --- a/target/arm/syndrome.h
> +++ b/target/arm/syndrome.h
> @@ -367,12 +367,21 @@ static inline uint32_t syn_sve_access_trap(void)
>   }
>   
>   /*
> + * ISS encoding for an exception from an ERET, ERETAA or ERETAB
> + * instructions.
> + *
>    * eret_op is bits [1:0] of the ERET instruction, so:
>    * 0 for ERET, 2 for ERETAA, 3 for ERETAB.
>    */
> +FIELD(ERET_ISS, OP, 0, 2)
> +
>   static inline uint32_t syn_erettrap(int eret_op)
>   {
> -    return (EC_ERETTRAP << ARM_EL_EC_SHIFT) | ARM_EL_IL | eret_op;
> +    uint32_t res = syn_set_ec(0, EC_ERETTRAP);
> +    res = FIELD_DP32(res, SYNDROME, IL, 1);
> +    res = FIELD_DP32(res, ERET_ISS, OP, eret_op);
> +
> +    return res;
>   }
>   
>   static inline uint32_t syn_smetrap(SMEExceptionType etype, bool is_16bit)

Reviewed-by: Richard Henderson <richard.henderson@linaro.org>

r~


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

* Re: [RFC PATCH 05/35] target/arm: migrate SME trap syndromes to registerfields
  2026-03-20 13:05 ` [RFC PATCH 05/35] target/arm: migrate SME " Alex Bennée
@ 2026-04-05 23:22   ` Richard Henderson
  0 siblings, 0 replies; 74+ messages in thread
From: Richard Henderson @ 2026-04-05 23:22 UTC (permalink / raw)
  To: qemu-devel

On 3/21/26 00:05, Alex Bennée wrote:
> Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
> ---
>   target/arm/syndrome.h | 12 ++++++++++--
>   1 file changed, 10 insertions(+), 2 deletions(-)
> 
> diff --git a/target/arm/syndrome.h b/target/arm/syndrome.h
> index b145a52769f..abec0a4908e 100644
> --- a/target/arm/syndrome.h
> +++ b/target/arm/syndrome.h
> @@ -384,10 +384,18 @@ static inline uint32_t syn_erettrap(int eret_op)
>       return res;
>   }
>   
> +/*
> + * ISS encoding for an exception due to SME functionality
> + */
> +FIELD(SME_ISS, SMTC, 0, 2)
> +
>   static inline uint32_t syn_smetrap(SMEExceptionType etype, bool is_16bit)
>   {
> -    return (EC_SMETRAP << ARM_EL_EC_SHIFT)
> -        | (is_16bit ? 0 : ARM_EL_IL) | etype;
> +    uint32_t res = syn_set_ec(0, EC_SMETRAP);
> +    res = FIELD_DP32(res, SYNDROME, IL, is_16bit ? 0 : 1);
> +    res = FIELD_DP32(res, SME_ISS, SMTC, etype);
> +
> +    return res;
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>

r~


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

* Re: [RFC PATCH 06/35] target/arm: migrate PAC trap syndromes to registerfields
  2026-03-20 13:05 ` [RFC PATCH 06/35] target/arm: migrate PAC " Alex Bennée
@ 2026-04-05 23:23   ` Richard Henderson
  0 siblings, 0 replies; 74+ messages in thread
From: Richard Henderson @ 2026-04-05 23:23 UTC (permalink / raw)
  To: qemu-devel

On 3/21/26 00:05, Alex Bennée wrote:
> syn_pactrap is fairly simple as the ISS is all RES0.
> 
> Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
> ---
>   target/arm/syndrome.h | 23 ++++++++++++++++++++---
>   1 file changed, 20 insertions(+), 3 deletions(-)

Reviewed-by: Richard Henderson <richard.henderson@linaro.org>

r~



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

* Re: [RFC PATCH 07/35] target/arm: migrate BTI trap syndromes to registerfields
  2026-03-20 13:05 ` [RFC PATCH 07/35] target/arm: migrate BTI " Alex Bennée
@ 2026-04-05 23:28   ` Richard Henderson
  0 siblings, 0 replies; 74+ messages in thread
From: Richard Henderson @ 2026-04-05 23:28 UTC (permalink / raw)
  To: qemu-devel

On 3/21/26 00:05, Alex Bennée wrote:
> Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
> ---
>   target/arm/syndrome.h | 11 ++++++++++-
>   1 file changed, 10 insertions(+), 1 deletion(-)
> 
> diff --git a/target/arm/syndrome.h b/target/arm/syndrome.h
> index 19c7659fb4f..0520e51a686 100644
> --- a/target/arm/syndrome.h
> +++ b/target/arm/syndrome.h
> @@ -426,9 +426,18 @@ static inline uint32_t syn_pactrap(void)
>       return res;
>   }
>   
> +/*
> + * ISS encoding for an exception from a Branch Target Identification
> + * instruction.
> + */
> +FIELD(BTI_ISS, BTYPE, 0, 2)
> +
>   static inline uint32_t syn_btitrap(int btype)
>   {
> -    return (EC_BTITRAP << ARM_EL_EC_SHIFT) | ARM_EL_IL | btype;
> +    uint32_t res = syn_set_ec(0, EC_BTITRAP);
> +    res = FIELD_DP32(res, SYNDROME, IL, 1);
> +    res = FIELD_DP32(res, BTI_ISS, BTYPE, btype);
> +    return res;
>   }
>   
>   static inline uint32_t syn_bxjtrap(int cv, int cond, int rm)

Reviewed-by: Richard Henderson <richard.henderson@linaro.org>

r~


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

* Re: [RFC PATCH 08/35] target/arm: migrate BXJ trap syndromes to registerfields
  2026-03-20 13:05 ` [RFC PATCH 08/35] target/arm: migrate BXJ " Alex Bennée
@ 2026-04-05 23:29   ` Richard Henderson
  0 siblings, 0 replies; 74+ messages in thread
From: Richard Henderson @ 2026-04-05 23:29 UTC (permalink / raw)
  To: qemu-devel

On 3/21/26 00:05, Alex Bennée wrote:
> This is an Armv7 specific syndrome for chips with Jazelle
> functionality.
> 
> Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
> ---
>   target/arm/syndrome.h | 20 ++++++++++++++++++--
>   1 file changed, 18 insertions(+), 2 deletions(-)
> 
> diff --git a/target/arm/syndrome.h b/target/arm/syndrome.h
> index 0520e51a686..fb86e7bf6a8 100644
> --- a/target/arm/syndrome.h
> +++ b/target/arm/syndrome.h
> @@ -440,10 +440,26 @@ static inline uint32_t syn_btitrap(int btype)
>       return res;
>   }
>   
> +/*
> + * ISS encoding for trapped BXJ execution
> + *
> + * This is an Armv7 encoding.
> + */
> +FIELD(BXJ_ISS, RM, 0, 4)
> +/* bits 4:19 are Reserved, UNK/SBZP */
> +FIELD(BXJ_ISS, COND, 20, 4)
> +FIELD(BXJ_ISS, CV, 24, 1)
> +
>   static inline uint32_t syn_bxjtrap(int cv, int cond, int rm)
>   {
> -    return (EC_BXJTRAP << ARM_EL_EC_SHIFT) | ARM_EL_IL |
> -        (cv << 24) | (cond << 20) | rm;
> +    uint32_t res = syn_set_ec(0, EC_BXJTRAP);
> +    res = FIELD_DP32(res, SYNDROME, IL, 1);
> +
> +    res = FIELD_DP32(res, BXJ_ISS, CV, cv);
> +    res = FIELD_DP32(res, BXJ_ISS, COND, cond);
> +    res = FIELD_DP32(res, BXJ_ISS, RM, rm);
> +
> +    return res;
>   }
>   
>   static inline uint32_t syn_gpc(int s2ptw, int ind, int gpcsc, int vncr,

Reviewed-by: Richard Henderson <richard.henderson@linaro.org>

r~


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

* Re: [RFC PATCH 09/35] target/arm: migrate Granule Protection traps to registerfields
  2026-03-20 13:05 ` [RFC PATCH 09/35] target/arm: migrate Granule Protection traps " Alex Bennée
@ 2026-04-05 23:30   ` Richard Henderson
  0 siblings, 0 replies; 74+ messages in thread
From: Richard Henderson @ 2026-04-05 23:30 UTC (permalink / raw)
  To: qemu-devel

On 3/21/26 00:05, Alex Bennée wrote:
> Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
> ---
>   target/arm/syndrome.h | 30 +++++++++++++++++++++++++++---
>   1 file changed, 27 insertions(+), 3 deletions(-)

Reviewed-by: Richard Henderson <richard.henderson@linaro.org>

r~

> 
> diff --git a/target/arm/syndrome.h b/target/arm/syndrome.h
> index fb86e7bf6a8..3fd82f5b565 100644
> --- a/target/arm/syndrome.h
> +++ b/target/arm/syndrome.h
> @@ -462,12 +462,36 @@ static inline uint32_t syn_bxjtrap(int cv, int cond, int rm)
>       return res;
>   }
>   
> +/*
> + * ISS encoding for a Granule Protection Check exception
> + *
> + * These are only reported to EL3
> + */
> +FIELD(GPC_ISS, xFSC, 0, 6)
> +FIELD(GPC_ISS, WnR, 6, 1) /* Write not Read */
> +FIELD(GPC_ISS, S1PTW, 7, 1)
> +FIELD(GPC_ISS, CM, 8, 1)
> +FIELD(GPC_ISS, VNCR, 13, 1)
> +FIELD(GPC_ISS, GPCSC, 14, 6)
> +FIELD(GPC_ISS, InD, 20, 1) /* Instruction not Data access */
> +FIELD(GPC_ISS, S2PTW, 21, 1)
> +
>   static inline uint32_t syn_gpc(int s2ptw, int ind, int gpcsc, int vncr,
>                                  int cm, int s1ptw, int wnr, int fsc)
>   {
> -    return (EC_GPC << ARM_EL_EC_SHIFT) | ARM_EL_IL | (s2ptw << 21)
> -        | (ind << 20) | (gpcsc << 14) | (vncr << 13) | (cm << 8)
> -        | (s1ptw << 7) | (wnr << 6) | fsc;
> +    uint32_t res = syn_set_ec(0, EC_GPC);
> +    res = FIELD_DP32(res, SYNDROME, IL, 1);
> +
> +    res = FIELD_DP32(res, GPC_ISS, S2PTW, s2ptw);
> +    res = FIELD_DP32(res, GPC_ISS, InD, ind);
> +    res = FIELD_DP32(res, GPC_ISS, GPCSC, gpcsc);
> +    res = FIELD_DP32(res, GPC_ISS, VNCR, vncr);
> +    res = FIELD_DP32(res, GPC_ISS, CM, cm);
> +    res = FIELD_DP32(res, GPC_ISS, S1PTW, s1ptw);
> +    res = FIELD_DP32(res, GPC_ISS, WnR, wnr);
> +    res = FIELD_DP32(res, GPC_ISS, xFSC, fsc);
> +
> +    return res;
>   }
>   
>   static inline uint32_t syn_insn_abort(int same_el, int ea, int s1ptw, int fsc)



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

* Re: [RFC PATCH 10/35] target/arm: migrate fault syndromes to registerfields
  2026-03-20 13:05 ` [RFC PATCH 10/35] target/arm: migrate fault syndromes " Alex Bennée
@ 2026-04-05 23:32   ` Richard Henderson
  0 siblings, 0 replies; 74+ messages in thread
From: Richard Henderson @ 2026-04-05 23:32 UTC (permalink / raw)
  To: qemu-devel

On 3/21/26 00:05, Alex Bennée wrote:
> Migrate syn_insn_abort and syn_data_abort_* to the registerfields API.
> 
> Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
> ---
>   target/arm/syndrome.h | 87 ++++++++++++++++++++++++++++++++++++-------
>   1 file changed, 74 insertions(+), 13 deletions(-)

Reviewed-by: Richard Henderson <richard.henderson@linaro.org>


r~



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

* Re: [RFC PATCH 11/35] target/arm: migrate debug syndromes to registerfields
  2026-03-20 13:05 ` [RFC PATCH 11/35] target/arm: migrate debug " Alex Bennée
@ 2026-04-05 23:37   ` Richard Henderson
  0 siblings, 0 replies; 74+ messages in thread
From: Richard Henderson @ 2026-04-05 23:37 UTC (permalink / raw)
  To: qemu-devel

On 3/21/26 00:05, Alex Bennée wrote:
> Migrate syn_swstep, syn_watchpoint and syn_breakpoint to the
> registerfields API.
> 
> Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
> ---
>   target/arm/syndrome.h | 54 ++++++++++++++++++++++++++++++++++++++-----
>   1 file changed, 48 insertions(+), 6 deletions(-)

Reviewed-by: Richard Henderson <richard.henderson@linaro.org>

r~



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

* Re: [RFC PATCH 12/35] target/arm: migrate wfx syndromes to registerfields
  2026-03-20 13:05 ` [RFC PATCH 12/35] target/arm: migrate wfx " Alex Bennée
@ 2026-04-05 23:41   ` Richard Henderson
  0 siblings, 0 replies; 74+ messages in thread
From: Richard Henderson @ 2026-04-05 23:41 UTC (permalink / raw)
  To: qemu-devel

On 3/21/26 00:05, Alex Bennée wrote:
> This will help later when we expand the fields we report.
> 
> Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
> ---
>   target/arm/syndrome.h | 20 +++++++++++++++++---
>   1 file changed, 17 insertions(+), 3 deletions(-)
> 
> diff --git a/target/arm/syndrome.h b/target/arm/syndrome.h
> index 3bd98a30367..503b19b5d02 100644
> --- a/target/arm/syndrome.h
> +++ b/target/arm/syndrome.h
> @@ -655,11 +655,25 @@ static inline uint32_t syn_breakpoint(int same_el)
>       return res;
>   }
>   
> +/*
> + * ISS encoding for an exception from a WF* instruction
> + */
> +FIELD(WFX_ISS, TI, 0, 2)
> +FIELD(WFX_ISS, RV, 2, 1)
> +FIELD(WFX_ISS, RN, 5, 5)
> +FIELD(WFX_ISS, COND, 20, 4)
> +FIELD(WFX_ISS, CV, 24, 1)
> +
>   static inline uint32_t syn_wfx(int cv, int cond, int ti, bool is_16bit)
>   {
> -    return (EC_WFX_TRAP << ARM_EL_EC_SHIFT) |
> -           (is_16bit ? 0 : (1 << ARM_EL_IL_SHIFT)) |
> -           (cv << 24) | (cond << 20) | ti;
> +    uint32_t res = syn_set_ec(0, EC_WFX_TRAP);
> +    res = FIELD_DP32(res, SYNDROME, IL, is_16bit ? 0 : 1);
> +
> +    res = FIELD_DP32(res, WFX_ISS, CV, cv);
> +    res = FIELD_DP32(res, WFX_ISS, COND, cond);
> +    res = FIELD_DP32(res, WFX_ISS, TI, ti);
> +
> +    return res;
>   }
>   
>   static inline uint32_t syn_illegalstate(void)

Reviewed-by: Richard Henderson <richard.henderson@linaro.org>

r~


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

* Re: [RFC PATCH 13/35] target/arm: migrate gcs syndromes to registerfields
  2026-03-20 13:05 ` [RFC PATCH 13/35] target/arm: migrate gcs " Alex Bennée
@ 2026-04-05 23:43   ` Richard Henderson
  0 siblings, 0 replies; 74+ messages in thread
From: Richard Henderson @ 2026-04-05 23:43 UTC (permalink / raw)
  To: qemu-devel

On 3/21/26 00:05, Alex Bennée wrote:
> Added a little comment to explain the RADDR<->ra mismatch.

Or you could just rename the argument.

Anyway,
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>

r~

> 
> Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
> ---
>   target/arm/syndrome.h | 38 +++++++++++++++++++++++++++++++++-----
>   1 file changed, 33 insertions(+), 5 deletions(-)
> 
> diff --git a/target/arm/syndrome.h b/target/arm/syndrome.h
> index 503b19b5d02..76f66b3beef 100644
> --- a/target/arm/syndrome.h
> +++ b/target/arm/syndrome.h
> @@ -690,21 +690,49 @@ static inline uint32_t syn_pcalignment(void)
>       return res;
>   }
>   
> +/*
> + * ISS encoding for a GCS exception
> + *
> + * Field validity depends on EXTYPE
> + */
> +FIELD(GCS_ISS, IT, 0, 5)
> +FIELD(GCS_ISS, RN, 5, 5) /* only for non EXLOCK exceptions */
> +FIELD(GCS_ISS, RADDR, 10, 5) /* only for GCSSTR/GCSSTTR traps */
> +FIELD(GCS_ISS, EXTYPE, 20, 4)
> +
>   static inline uint32_t syn_gcs_data_check(GCSInstructionType it, int rn)
>   {
> -    return ((EC_GCS << ARM_EL_EC_SHIFT) | ARM_EL_IL |
> -            (GCS_ET_DataCheck << 20) | (rn << 5) | it);
> +    uint32_t res = syn_set_ec(0, EC_GCS);
> +    res = FIELD_DP32(res, SYNDROME, IL, 1);
> +
> +    res = FIELD_DP32(res, GCS_ISS, EXTYPE, GCS_ET_DataCheck);
> +    res = FIELD_DP32(res, GCS_ISS, RN, rn);
> +    res = FIELD_DP32(res, GCS_ISS, IT, it);
> +
> +    return res;
>   }
>   
>   static inline uint32_t syn_gcs_exlock(void)
>   {
> -    return (EC_GCS << ARM_EL_EC_SHIFT) | ARM_EL_IL | (GCS_ET_EXLOCK << 20);
> +    uint32_t res = syn_set_ec(0, EC_GCS);
> +    res = FIELD_DP32(res, SYNDROME, IL, 1);
> +
> +    res = FIELD_DP32(res, GCS_ISS, EXTYPE, GCS_ET_EXLOCK);
> +
> +    return res;
>   }
>   
>   static inline uint32_t syn_gcs_gcsstr(int ra, int rn)
>   {
> -    return ((EC_GCS << ARM_EL_EC_SHIFT) | ARM_EL_IL |
> -            (GCS_ET_GCSSTR_GCSSTTR << 20) | (ra << 10) | (rn << 5));
> +    uint32_t res = syn_set_ec(0, EC_GCS);
> +    res = FIELD_DP32(res, SYNDROME, IL, 1);
> +
> +    res = FIELD_DP32(res, GCS_ISS, EXTYPE, GCS_ET_GCSSTR_GCSSTTR);
> +    /* when ExType == 0b0010 RADDR is the data register */
> +    res = FIELD_DP32(res, GCS_ISS, RADDR, ra);
> +    res = FIELD_DP32(res, GCS_ISS, RN, rn);
> +
> +    return res;
>   }
>   
>   static inline uint32_t syn_serror(uint32_t extra)



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

* Re: [RFC PATCH 14/35] target/arm: migrate memory op syndromes to registerfields
  2026-03-20 13:05 ` [RFC PATCH 14/35] target/arm: migrate memory op " Alex Bennée
@ 2026-04-05 23:44   ` Richard Henderson
  0 siblings, 0 replies; 74+ messages in thread
From: Richard Henderson @ 2026-04-05 23:44 UTC (permalink / raw)
  To: qemu-devel

On 3/21/26 00:05, Alex Bennée wrote:
> Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
> ---
>   target/arm/syndrome.h | 33 +++++++++++++++++++++++++++++----
>   1 file changed, 29 insertions(+), 4 deletions(-)

Reviewed-by: Richard Henderson <richard.henderson@linaro.org>

r~



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

* Re: [RFC PATCH 15/35] target/arm: migrate check_hcr_el2_trap to use syndrome helper
  2026-03-20 13:05 ` [RFC PATCH 15/35] target/arm: migrate check_hcr_el2_trap to use syndrome helper Alex Bennée
@ 2026-04-06  0:01   ` Richard Henderson
  0 siblings, 0 replies; 74+ messages in thread
From: Richard Henderson @ 2026-04-06  0:01 UTC (permalink / raw)
  To: qemu-devel

On 3/21/26 00:05, Alex Bennée wrote:
> It shares the same COPROC_ISS encoding as the other CP traps although
> not all the fields are used.
> 
> Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
> ---
>   target/arm/syndrome.h       | 16 ++++++++++++++++
>   target/arm/tcg/vfp_helper.c |  5 +----
>   2 files changed, 17 insertions(+), 4 deletions(-)

Reviewed-by: Richard Henderson <richard.henderson@linaro.org>

r~

> 
> diff --git a/target/arm/syndrome.h b/target/arm/syndrome.h
> index 2e3121aec9c..4fbc35ce7b0 100644
> --- a/target/arm/syndrome.h
> +++ b/target/arm/syndrome.h
> @@ -251,6 +251,22 @@ FIELD(COPROC_ISS, OP2, 17, 3)
>   FIELD(COPROC_ISS, COND, 20, 4)
>   FIELD(COPROC_ISS, CV, 24, 1)
>   
> +static inline uint32_t syn_cp10_rt_trap(int cv, int cond, int opc1,
> +                                        int crn, int rt, int isread)
> +{
> +    uint32_t res = syn_set_ec(0, EC_FPIDTRAP);
> +    res = FIELD_DP32(res, SYNDROME, IL, 1);
> +
> +    res = FIELD_DP32(res, COPROC_ISS, CV, cv);
> +    res = FIELD_DP32(res, COPROC_ISS, COND, cond);
> +    res = FIELD_DP32(res, COPROC_ISS, OP1, opc1);
> +    res = FIELD_DP32(res, COPROC_ISS, CRN, crn);
> +    res = FIELD_DP32(res, COPROC_ISS, RT, rt);
> +    res = FIELD_DP32(res, COPROC_ISS, ISREAD, isread);
> +
> +    return res;
> +}
> +
>   static inline uint32_t syn_cp14_rt_trap(int cv, int cond, int opc1, int opc2,
>                                           int crn, int crm, int rt, int isread,
>                                           bool is_16bit)
> diff --git a/target/arm/tcg/vfp_helper.c b/target/arm/tcg/vfp_helper.c
> index 45f2eb0930f..e692bc568bd 100644
> --- a/target/arm/tcg/vfp_helper.c
> +++ b/target/arm/tcg/vfp_helper.c
> @@ -1359,10 +1359,7 @@ void HELPER(check_hcr_el2_trap)(CPUARMState *env, uint32_t rt, uint32_t reg)
>           g_assert_not_reached();
>       }
>   
> -    syndrome = ((EC_FPIDTRAP << ARM_EL_EC_SHIFT)
> -                | ARM_EL_IL
> -                | (1 << 24) | (0xe << 20) | (7 << 14)
> -                | (reg << 10) | (rt << 5) | 1);
> +    syndrome = syn_cp10_rt_trap(1, 0xe, 7, reg, rt, 1);
>   
>       raise_exception(env, EXCP_HYP_TRAP, syndrome, 2);
>   }



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

* Re: [RFC PATCH 16/35] target/arm: use syndrome helpers in arm_cpu_do_interrupt_aarch32_hyp
  2026-03-20 13:05 ` [RFC PATCH 16/35] target/arm: use syndrome helpers in arm_cpu_do_interrupt_aarch32_hyp Alex Bennée
@ 2026-04-06  0:06   ` Richard Henderson
  0 siblings, 0 replies; 74+ messages in thread
From: Richard Henderson @ 2026-04-06  0:06 UTC (permalink / raw)
  To: qemu-devel

On 3/21/26 00:05, Alex Bennée wrote:
> One more step towards dropping the old #defines.
> 
> Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
> ---
>   target/arm/helper.c | 4 ++--
>   1 file changed, 2 insertions(+), 2 deletions(-)
> 
> diff --git a/target/arm/helper.c b/target/arm/helper.c
> index 7389f2988c4..5ee79f7564f 100644
> --- a/target/arm/helper.c
> +++ b/target/arm/helper.c
> @@ -8898,9 +8898,9 @@ static void arm_cpu_do_interrupt_aarch32_hyp(CPUState *cs)
>                */
>               if (cs->exception_index == EXCP_PREFETCH_ABORT ||
>                   (cs->exception_index == EXCP_DATA_ABORT &&
> -                 !(env->exception.syndrome & ARM_EL_ISV)) ||
> +                 !(FIELD_EX32(env->exception.syndrome, SYNDROME, IL))) ||

Unnecessary () around FIELD_EX32.

Otherwise,
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>


>                   syn_get_ec(env->exception.syndrome) == EC_UNCATEGORIZED) {
> -                env->exception.syndrome &= ~ARM_EL_IL;
> +                env->exception.syndrome = FIELD_DP32(env->exception.syndrome, SYNDROME, IL, 0);
>               }
>           }
>           env->cp15.esr_el[2] = env->exception.syndrome;



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

* Re: [RFC PATCH 17/35] target/arm: use syndrome helpers to set SAME_EL EC bit
  2026-03-20 13:05 ` [RFC PATCH 17/35] target/arm: use syndrome helpers to set SAME_EL EC bit Alex Bennée
@ 2026-04-06  0:07   ` Richard Henderson
  0 siblings, 0 replies; 74+ messages in thread
From: Richard Henderson @ 2026-04-06  0:07 UTC (permalink / raw)
  To: qemu-devel

On 3/21/26 00:05, Alex Bennée wrote:
> This removes the last use of ARM_EL_EC_SHIFT.

Why not remove it here then?

Anyway,
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>

r~

> 
> Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
> ---
>   target/arm/tcg/debug.c | 2 +-
>   1 file changed, 1 insertion(+), 1 deletion(-)
> 
> diff --git a/target/arm/tcg/debug.c b/target/arm/tcg/debug.c
> index 5214e3c08a8..07a52643e71 100644
> --- a/target/arm/tcg/debug.c
> +++ b/target/arm/tcg/debug.c
> @@ -56,7 +56,7 @@ raise_exception_debug(CPUARMState *env, uint32_t excp, uint32_t syndrome)
>        * Similarly for watchpoint and breakpoint matches.
>        */
>       assert(debug_el >= cur_el);
> -    syndrome |= (debug_el == cur_el) << ARM_EL_EC_SHIFT;
> +    syndrome |= (debug_el == cur_el) << R_SYNDROME_EC_SHIFT;
>       raise_exception(env, excp, syndrome, debug_el);
>   }
>   



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

* Re: [RFC PATCH 18/35] target/arm: make whpx use syndrome helpers for decode
  2026-03-20 13:05 ` [RFC PATCH 18/35] target/arm: make whpx use syndrome helpers for decode Alex Bennée
@ 2026-04-06  0:08   ` Richard Henderson
  0 siblings, 0 replies; 74+ messages in thread
From: Richard Henderson @ 2026-04-06  0:08 UTC (permalink / raw)
  To: qemu-devel

On 3/21/26 00:05, Alex Bennée wrote:
> Rather than open coding a bunch of shifts and masks we can use the
> syndrome definitions. While we are at it assert it really is a
> EC_DATAABORT.
> 
> Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
> ---
>   target/arm/whpx/whpx-all.c | 13 +++++++------
>   1 file changed, 7 insertions(+), 6 deletions(-)
> 
> diff --git a/target/arm/whpx/whpx-all.c b/target/arm/whpx/whpx-all.c
> index 513551bec1b..f5646e7127e 100644
> --- a/target/arm/whpx/whpx-all.c
> +++ b/target/arm/whpx/whpx-all.c
> @@ -356,15 +356,16 @@ static int whpx_handle_mmio(CPUState *cpu, WHV_MEMORY_ACCESS_CONTEXT *ctx)
>   {
>       uint64_t syndrome = ctx->Syndrome;
>   
> -    bool isv = syndrome & ARM_EL_ISV;
> -    bool iswrite = (syndrome >> 6) & 1;
> -    bool sse = (syndrome >> 21) & 1;
> -    uint32_t sas = (syndrome >> 22) & 3;
> +    bool isv = FIELD_EX32(syndrome, DABORT_ISS, ISV);
> +    bool iswrite = FIELD_EX32(syndrome, DABORT_ISS, WNR);
> +    bool sse = FIELD_EX32(syndrome, DABORT_ISS, SSE);
> +    uint32_t sas = FIELD_EX32(syndrome, DABORT_ISS, SAS);
>       uint32_t len = 1 << sas;
> -    uint32_t srt = (syndrome >> 16) & 0x1f;
> -    uint32_t cm = (syndrome >> 8) & 0x1;
> +    uint32_t srt = FIELD_EX32(syndrome, DABORT_ISS, SRT);
> +    uint32_t cm = FIELD_EX32(syndrome, DABORT_ISS, CM);
>       uint64_t val = 0;
>   
> +    assert(syn_get_ec(syndrome) == EC_DATAABORT);
>       assert(!cm);
>       assert(isv);
>   

Reviewed-by: Richard Henderson <richard.henderson@linaro.org>

r~


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

* Re: [RFC PATCH 19/35] target/arm: make hvf use syndrome helpers for decode
  2026-03-20 13:05 ` [RFC PATCH 19/35] target/arm: make hvf " Alex Bennée
@ 2026-04-06  0:08   ` Richard Henderson
  0 siblings, 0 replies; 74+ messages in thread
From: Richard Henderson @ 2026-04-06  0:08 UTC (permalink / raw)
  To: qemu-devel

On 3/21/26 00:05, Alex Bennée wrote:
> Rather than open coding a bunch of shifts and masks we can use the
> syndrome definitions.
> 
> Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
> ---
>   target/arm/hvf/hvf.c | 14 +++++++-------
>   1 file changed, 7 insertions(+), 7 deletions(-)
> 
> diff --git a/target/arm/hvf/hvf.c b/target/arm/hvf/hvf.c
> index 5fc8f6bbbd9..1c1c31f0b15 100644
> --- a/target/arm/hvf/hvf.c
> +++ b/target/arm/hvf/hvf.c
> @@ -2123,14 +2123,14 @@ static int hvf_handle_exception(CPUState *cpu, hv_vcpu_exit_exception_t *excp)
>           break;
>       }
>       case EC_DATAABORT: {
> -        bool isv = syndrome & ARM_EL_ISV;
> -        bool iswrite = (syndrome >> 6) & 1;
> -        bool s1ptw = (syndrome >> 7) & 1;
> -        bool sse = (syndrome >> 21) & 1;
> -        uint32_t sas = (syndrome >> 22) & 3;
> +        bool isv = FIELD_EX32(syndrome, DABORT_ISS, ISV);
> +        bool iswrite = FIELD_EX32(syndrome, DABORT_ISS, WNR);
> +        bool s1ptw = FIELD_EX32(syndrome, DABORT_ISS, S1PTW);
> +        bool sse = FIELD_EX32(syndrome, DABORT_ISS, SSE);
> +        uint32_t sas = FIELD_EX32(syndrome, DABORT_ISS, SAS);
>           uint32_t len = 1 << sas;
> -        uint32_t srt = (syndrome >> 16) & 0x1f;
> -        uint32_t cm = (syndrome >> 8) & 0x1;
> +        uint32_t srt = FIELD_EX32(syndrome, DABORT_ISS, SRT);
> +        uint32_t cm = FIELD_EX32(syndrome, DABORT_ISS, CM);
>           uint64_t val = 0;
>           uint64_t ipa = excp->physical_address;
>           AddressSpace *as = cpu_get_address_space(cpu, ARMASIdx_NS);

Reviewed-by: Richard Henderson <richard.henderson@linaro.org>

r~


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

* Re: [RFC PATCH 20/35] target/arm: use syndrome helpers in merge_syn_data_abort
  2026-03-20 13:05 ` [RFC PATCH 20/35] target/arm: use syndrome helpers in merge_syn_data_abort Alex Bennée
@ 2026-04-06  0:15   ` Richard Henderson
  0 siblings, 0 replies; 74+ messages in thread
From: Richard Henderson @ 2026-04-06  0:15 UTC (permalink / raw)
  To: qemu-devel

On 3/21/26 00:05, Alex Bennée wrote:
> One more step to removing the old defines.
> 
> Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
> ---
>   target/arm/tcg/tlb_helper.c | 2 +-
>   1 file changed, 1 insertion(+), 1 deletion(-)
> 
> diff --git a/target/arm/tcg/tlb_helper.c b/target/arm/tcg/tlb_helper.c
> index 565954269f9..c74d8e785a6 100644
> --- a/target/arm/tcg/tlb_helper.c
> +++ b/target/arm/tcg/tlb_helper.c
> @@ -56,7 +56,7 @@ static inline uint64_t merge_syn_data_abort(uint32_t template_syn,
>            */
>           assert(!fi->stage2);
>           syn = syn_data_abort_vncr(fi->ea, is_write, fsc);
> -    } else if (!(template_syn & ARM_EL_ISV) || target_el != 2
> +    } else if (!FIELD_EX32(template_syn, DABORT_ISS, ISV) || target_el != 2
>           || fi->s1ptw || !fi->stage2) {
>           syn = syn_data_abort_no_iss(same_el, 0,
>                                       fi->ea, 0, fi->s1ptw, is_write, fsc);

Reviewed-by: Richard Henderson <richard.henderson@linaro.org>

r~


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

* Re: [RFC PATCH 21/35] target/arm: use syndrome helpers to query VNCR bit
  2026-03-20 13:05 ` [RFC PATCH 21/35] target/arm: use syndrome helpers to query VNCR bit Alex Bennée
@ 2026-04-06  0:17   ` Richard Henderson
  0 siblings, 0 replies; 74+ messages in thread
From: Richard Henderson @ 2026-04-06  0:17 UTC (permalink / raw)
  To: qemu-devel

On 3/21/26 00:05, Alex Bennée wrote:
> These are only valid for data abort syndromes.
> 
> Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
> ---
>   target/arm/tcg/tlb_helper.c | 4 ++--
>   1 file changed, 2 insertions(+), 2 deletions(-)
> 
> diff --git a/target/arm/tcg/tlb_helper.c b/target/arm/tcg/tlb_helper.c
> index c74d8e785a6..bbe1e70bc43 100644
> --- a/target/arm/tcg/tlb_helper.c
> +++ b/target/arm/tcg/tlb_helper.c
> @@ -48,7 +48,7 @@ static inline uint64_t merge_syn_data_abort(uint32_t template_syn,
>        * ST64BV, or ST64BV0 insns report syndrome info even for stage-1
>        * faults and regardless of the target EL.
>        */
> -    if (template_syn & ARM_EL_VNCR) {
> +    if (FIELD_EX32(template_syn, DABORT_ISS, VNCR)) {
>           /*
>            * FEAT_NV2 faults on accesses via VNCR_EL2 are a special case:
>            * they are always reported as "same EL", even though we are going
> @@ -190,7 +190,7 @@ void arm_deliver_fault(ARMCPU *cpu, vaddr addr,
>        * because we masked that out in disas_set_insn_syndrome())
>        */
>       bool is_vncr = (access_type != MMU_INST_FETCH) &&
> -        (env->exception.syndrome & ARM_EL_VNCR);
> +        FIELD_EX32(env->exception.syndrome, DABORT_ISS, VNCR);
>   
>       if (is_vncr) {
>           /* FEAT_NV2 faults on accesses via VNCR_EL2 go to EL2 */

Reviewed-by: Richard Henderson <richard.henderson@linaro.org>

r~


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

* Re: [RFC PATCH 22/35] target/arm: remove old syndrome defines
  2026-03-20 13:05 ` [RFC PATCH 22/35] target/arm: remove old syndrome defines Alex Bennée
@ 2026-04-06  0:17   ` Richard Henderson
  0 siblings, 0 replies; 74+ messages in thread
From: Richard Henderson @ 2026-04-06  0:17 UTC (permalink / raw)
  To: qemu-devel

On 3/21/26 00:05, Alex Bennée wrote:
> Now everything is defined with registerfields we can drop the old
> defines.
> 
> Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
> ---
>   target/arm/syndrome.h | 10 ----------
>   1 file changed, 10 deletions(-)
> 
> diff --git a/target/arm/syndrome.h b/target/arm/syndrome.h
> index 4fbc35ce7b0..1887467b719 100644
> --- a/target/arm/syndrome.h
> +++ b/target/arm/syndrome.h
> @@ -106,16 +106,6 @@ typedef enum {
>       GCS_IT_GCSPOPX = 9,
>   } GCSInstructionType;
>   
> -#define ARM_EL_EC_LENGTH 6
> -#define ARM_EL_EC_SHIFT 26
> -#define ARM_EL_IL_SHIFT 25
> -#define ARM_EL_ISV_SHIFT 24
> -#define ARM_EL_IL (1 << ARM_EL_IL_SHIFT)
> -#define ARM_EL_ISV (1 << ARM_EL_ISV_SHIFT)
> -
> -/* In the Data Abort syndrome */
> -#define ARM_EL_VNCR (1 << 13)
> -
>   static inline uint32_t syn_get_ec(uint32_t syn)
>   {
>       return FIELD_EX32(syn, SYNDROME, EC);

Reviewed-by: Richard Henderson <richard.henderson@linaro.org>

r~


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

* Re: [RFC PATCH 23/35] target/arm: report register in WFIT syndromes
  2026-03-20 13:05 ` [RFC PATCH 23/35] target/arm: report register in WFIT syndromes Alex Bennée
@ 2026-04-06  0:24   ` Richard Henderson
  0 siblings, 0 replies; 74+ messages in thread
From: Richard Henderson @ 2026-04-06  0:24 UTC (permalink / raw)
  To: qemu-devel

On 3/21/26 00:05, Alex Bennée wrote:
> Pass the register number (rd) to the wfit helper and report it in the
> syndrome ISS. This also includes the correction of the TI bits for
> WFIT traps to 0b10.
> 
> TODO: split the helper flags
> 
> Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
> ---
>   target/arm/syndrome.h          | 4 +++-
>   target/arm/tcg/helper-defs.h   | 2 +-
>   target/arm/tcg/op_helper.c     | 7 ++++---
>   target/arm/tcg/translate-a64.c | 2 +-
>   4 files changed, 9 insertions(+), 6 deletions(-)
> 
> diff --git a/target/arm/syndrome.h b/target/arm/syndrome.h
> index 1887467b719..f303c41d71a 100644
> --- a/target/arm/syndrome.h
> +++ b/target/arm/syndrome.h
> @@ -670,7 +670,7 @@ FIELD(WFX_ISS, RN, 5, 5)
>   FIELD(WFX_ISS, COND, 20, 4)
>   FIELD(WFX_ISS, CV, 24, 1)
>   
> -static inline uint32_t syn_wfx(int cv, int cond, int ti, bool is_16bit)
> +static inline uint32_t syn_wfx(int cv, int cond, int rn, int rv, int ti, bool is_16bit)

rv, register valid, should be boolean, yes?

Otherwise,
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>


r~


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

* Re: [RFC PATCH 25/35] target/arm: redefine event stream fields
  2026-03-20 13:05 ` [RFC PATCH 25/35] target/arm: redefine event stream fields Alex Bennée
@ 2026-04-06  0:30   ` Richard Henderson
  0 siblings, 0 replies; 74+ messages in thread
From: Richard Henderson @ 2026-04-06  0:30 UTC (permalink / raw)
  To: qemu-devel

On 3/21/26 00:05, Alex Bennée wrote:
> The event stream control bits are the same for both CNTHCTL and
> CNTKCTL so rather than duplicating the definitions rename them to be
> useful in both cases.
> 
> We will need these in a later commit when we start implementing event
> streams.
> 
> Signed-off-by: Alex Bennée<alex.bennee@linaro.org>
> ---
>   target/arm/internals.h | 11 +++++++----
>   target/arm/helper.c    |  8 ++++----
>   2 files changed, 11 insertions(+), 8 deletions(-)

Reviewed-by: Richard Henderson <richard.henderson@linaro.org>

r~


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

* Re: [RFC PATCH 26/35] target/arm: add gt_calc_next_event_stream
  2026-03-20 13:05 ` [RFC PATCH 26/35] target/arm: add gt_calc_next_event_stream Alex Bennée
@ 2026-04-06  0:34   ` Richard Henderson
  0 siblings, 0 replies; 74+ messages in thread
From: Richard Henderson @ 2026-04-06  0:34 UTC (permalink / raw)
  To: qemu-devel

On 3/21/26 00:05, Alex Bennée wrote:
> Two generic timers (K and H) are capable of generating timer event
> stream events. Provide a helper to calculate when the nearest one will
> happen. This will eventually be used when implementing WFE/WFET.
> 
> Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
> ---
>   target/arm/cpu.h    | 10 ++++++
>   target/arm/helper.c | 85 +++++++++++++++++++++++++++++++++++++++++++++
>   2 files changed, 95 insertions(+)
> 
> diff --git a/target/arm/cpu.h b/target/arm/cpu.h
> index 657ff4ab20b..bf6cf74c2e1 100644
> --- a/target/arm/cpu.h
> +++ b/target/arm/cpu.h
> @@ -1208,6 +1208,16 @@ void arm_gt_sel2vtimer_cb(void *opaque);
>   unsigned int gt_cntfrq_period_ns(ARMCPU *cpu);
>   void gt_rme_post_el_change(ARMCPU *cpu, void *opaque);
>   
> +/**
> + * gt_calc_next_event_stream() - calculate and arm event stream timer
> + * @env: CPUArmState
> + *
> + * Calculate the next event stream time and return it. Returns -1 if
> + * no event streams are enabled. It is up to the WFE helpers to decide
> + * on the next time.
> + */
> +int64_t gt_calc_next_event_stream(CPUARMState *env);

Why cpu.h?  Where is this going to be used?

r~

> +
>   #define ARM_AFF0_SHIFT 0
>   #define ARM_AFF0_MASK  (0xFFULL << ARM_AFF0_SHIFT)
>   #define ARM_AFF1_SHIFT 8
> diff --git a/target/arm/helper.c b/target/arm/helper.c
> index ba6db46d453..3627ffcdcfd 100644
> --- a/target/arm/helper.c
> +++ b/target/arm/helper.c
> @@ -25,6 +25,7 @@
>   #include "exec/icount.h"
>   #include "system/kvm.h"
>   #include "system/tcg.h"
> +#include "system/cpus.h"
>   #include "qapi/error.h"
>   #include "qemu/guest-random.h"
>   #ifdef CONFIG_TCG
> @@ -2022,6 +2023,90 @@ void arm_gt_hvtimer_cb(void *opaque)
>       gt_recalc_timer(cpu, GTIMER_HYPVIRT);
>   }
>   
> +/*
> + * Event Stream events don't do anything apart from wake up sleeping
> + * cores. These helpers calculate the next event stream event time so
> + * the WFE helper can decide when its next wake up tick will be.
> + */
> +static int64_t gt_recalc_one_evt(CPUARMState *env, uint32_t control, uint64_t offset)
> +{
> +    ARMCPU *cpu = env_archcpu(env);
> +    bool evnten = FIELD_EX32(control, CNTxCTL, EVNTEN);
> +
> +    if (evnten) {
> +        int evnti = FIELD_EX32(control, CNTxCTL, EVNTI);
> +        bool evntis = FIELD_EX32(control, CNTxCTL, EVNTIS);
> +        bool evntdir = FIELD_EX32(control, CNTxCTL, EVNTDIR);
> +        /*
> +         * To figure out when the next event timer should fire we need
> +         * to calculate which bit of the counter we want to flip and
> +         * which transition counts.
> +         *
> +         * So we calculate 1 << bit - current lower bits and then add
> +         * 1 << bit if the bit needs to flip twice to meet evntdir
> +         */
> +        int bit = evntis ? evnti + 8 : evnti;
> +        uint64_t count = gt_get_countervalue(env) - offset;
> +        uint64_t target_bit = BIT_ULL(bit);
> +        uint64_t lower_bits = MAKE_64BIT_MASK(0, bit - 1);
> +        uint64_t next_tick = target_bit - (count & lower_bits);
> +        uint64_t abstick;
> +
> +        /* do we need to bit flip twice? */
> +        if (((count & target_bit) != 0) ^ evntdir) {
> +            next_tick += target_bit;
> +        }
> +
> +        /*
> +         * Note that the desired next expiry time might be beyond the
> +         * signed-64-bit range of a QEMUTimer -- in this case we just
> +         * set the timer for as far in the future as possible. When the
> +         * timer expires we will reset the timer for any remaining period.
> +         */
> +        if (uadd64_overflow(next_tick, offset, &abstick)) {
> +            abstick = UINT64_MAX;
> +        }
> +        if (abstick > INT64_MAX / gt_cntfrq_period_ns(cpu)) {
> +            return INT64_MAX;
> +        } else {
> +            return abstick;
> +        }
> +    }
> +
> +    return -1;
> +}
> +
> +int64_t gt_calc_next_event_stream(CPUARMState *env)
> +{
> +    ARMCPU *cpu = env_archcpu(env);
> +    uint64_t hcr = arm_hcr_el2_eff(env);
> +    int64_t next_time = -1;
> +    uint64_t offset;
> +
> +    /* Unless we are missing EL2 this can generate events */
> +    if (arm_feature(env, ARM_FEATURE_EL2)) {
> +        offset = gt_direct_access_timer_offset(env, GTIMER_PHYS);
> +        next_time = gt_recalc_one_evt(env, env->cp15.cnthctl_el2, offset);
> +    }
> +
> +    /* Event stream events from virtual counter enabled? */
> +    if (!cpu_isar_feature(aa64_vh, cpu) ||
> +        !((hcr & (HCR_E2H | HCR_TGE)) == (HCR_E2H | HCR_TGE))) {
> +        int64_t next_virt_time;
> +        offset = gt_direct_access_timer_offset(env, GTIMER_VIRT);
> +        next_virt_time = gt_recalc_one_evt(env, env->cp15.c14_cntkctl, offset);
> +
> +        /* is this earlier than the next physical event? */
> +        if (next_virt_time > 0) {
> +            if (next_time < 0 || next_virt_time < next_time) {
> +                next_time = next_virt_time;
> +            }
> +        }
> +    }
> +
> +    return next_time;
> +}
> +
>   static const ARMCPRegInfo generic_timer_cp_reginfo[] = {
>       /*
>        * Note that CNTFRQ is purely reads-as-written for the benefit



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

* Re: [RFC PATCH 27/35] target/arm: wrap event_register in a union
  2026-03-20 13:05 ` [RFC PATCH 27/35] target/arm: wrap event_register in a union Alex Bennée
@ 2026-04-06  0:37   ` Richard Henderson
  2026-04-07 10:35     ` Alex Bennée
  0 siblings, 1 reply; 74+ messages in thread
From: Richard Henderson @ 2026-04-06  0:37 UTC (permalink / raw)
  To: qemu-devel

On 3/21/26 00:05, Alex Bennée wrote:
> While the event register is either set or not due to the
> implementation defined nature of bool types we can't set it directly
> from TCG code. By wrapping in a union we can alias a 32 bit value to
> the bool in a future patch.
> 
> Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
> ---
>   target/arm/cpu.h           | 9 +++++++--
>   hw/intc/armv7m_nvic.c      | 2 +-
>   target/arm/machine.c       | 4 ++--
>   target/arm/tcg/m_helper.c  | 4 ++--
>   target/arm/tcg/op_helper.c | 6 +++---
>   5 files changed, 15 insertions(+), 10 deletions(-)
> 
> diff --git a/target/arm/cpu.h b/target/arm/cpu.h
> index bf6cf74c2e1..9c25b60ae83 100644
> --- a/target/arm/cpu.h
> +++ b/target/arm/cpu.h
> @@ -763,9 +763,14 @@ typedef struct CPUArchState {
>       /*
>        * The event register is shared by all ARM profiles (A/R/M),
>        * so it is stored in the top-level CPU state.
> -     * WFE/SEV handling is currently implemented only for M-profile.
> +     *
> +     * It is treated as a boolean but we need the union so we can set
> +     * it from TCG.
>        */
> -    bool event_register;
> +    union {
> +        bool as_bool;
> +        uint32_t as_uint32;
> +    } event_register;

What are you attempting here?  This smells like a big-endian bug.

TCG is certainly capable of storing to a bool, via tcg_gen_st8_*.


r~



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

* Re: [RFC PATCH 28/35] target/arm: ensure aarch64 DISAS_WFE will exit
  2026-03-20 13:05 ` [RFC PATCH 28/35] target/arm: ensure aarch64 DISAS_WFE will exit Alex Bennée
@ 2026-04-06  3:00   ` Richard Henderson
  0 siblings, 0 replies; 74+ messages in thread
From: Richard Henderson @ 2026-04-06  3:00 UTC (permalink / raw)
  To: Alex Bennée, qemu-devel
  Cc: Alexander Graf, Peter Maydell, qemu-arm, Pedro Barbuda,
	Mohamed Mediouni

On 3/21/26 00:05, Alex Bennée wrote:
> This mirrors the logic for DISAS_WFE in 32 bit world.
> 
> Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
> ---
>   target/arm/tcg/translate-a64.c | 1 +
>   1 file changed, 1 insertion(+)
> 
> diff --git a/target/arm/tcg/translate-a64.c b/target/arm/tcg/translate-a64.c
> index 073454b9195..d79c8ab431b 100644
> --- a/target/arm/tcg/translate-a64.c
> +++ b/target/arm/tcg/translate-a64.c
> @@ -10917,6 +10917,7 @@ static void aarch64_tr_tb_stop(DisasContextBase *dcbase, CPUState *cpu)
>           case DISAS_WFE:
>               gen_a64_update_pc(dc, 4);
>               gen_helper_wfe(tcg_env);
> +            tcg_gen_exit_tb(NULL, 0);
>               break;
>           case DISAS_YIELD:
>               gen_a64_update_pc(dc, 4);

This appears to be wrong since 252ec405768 (2014).

Reviewed-by: Richard Henderson <richard.henderson@linaro.org>


r~


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

* Re: [RFC PATCH 29/35] target/arm: implements SEV/SEVL for all modes
  2026-03-20 13:06 ` [RFC PATCH 29/35] target/arm: implements SEV/SEVL for all modes Alex Bennée
@ 2026-04-06  3:22   ` Richard Henderson
  0 siblings, 0 replies; 74+ messages in thread
From: Richard Henderson @ 2026-04-06  3:22 UTC (permalink / raw)
  To: qemu-devel

On 3/21/26 00:06, Alex Bennée wrote:
> Remove the restrictions that make this a M-profile only operation and
> enable the instructions for all Arm instructions.
> 
> Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
> ---
>   target/arm/tcg/a32.decode      |  5 ++---
>   target/arm/tcg/a64.decode      |  5 ++---
>   target/arm/tcg/t16.decode      |  4 +---
>   target/arm/tcg/t32.decode      |  4 +---
>   target/arm/tcg/op_helper.c     |  4 +---
>   target/arm/tcg/translate-a64.c | 34 ++++++++++++++++++++++++++++++++++
>   target/arm/tcg/translate.c     | 19 ++++++++++++++-----
>   7 files changed, 55 insertions(+), 20 deletions(-)
> 
> diff --git a/target/arm/tcg/a32.decode b/target/arm/tcg/a32.decode
> index f2ca4809495..d076681bf97 100644
> --- a/target/arm/tcg/a32.decode
> +++ b/target/arm/tcg/a32.decode
> @@ -192,9 +192,8 @@ SMULTT           .... 0001 0110 .... 0000 .... 1110 ....      @rd0mn
>         WFE        ---- 0011 0010 0000 1111 ---- 0000 0010
>         WFI        ---- 0011 0010 0000 1111 ---- 0000 0011
>   
> -      # TODO: Implement SEV, SEVL; may help SMP performance.
> -      # SEV      ---- 0011 0010 0000 1111 ---- 0000 0100
> -      # SEVL     ---- 0011 0010 0000 1111 ---- 0000 0101
> +      SEV      ---- 0011 0010 0000 1111 ---- 0000 0100
> +      SEVL     ---- 0011 0010 0000 1111 ---- 0000 0101
>   
>         ESB        ---- 0011 0010 0000 1111 ---- 0001 0000

Preserve the column alignment.

> +/*
> + * Event Register signalling.
> + *
> + * A bunch of activities trigger events, we just need to latch on to
> + * true. The event eventually gets consumed by WFE/WFET.
> + *
> + * user-mode treats these as nops.
> + */
> +
> +static void gen_event_reg(void)
> +{
> +#ifndef CONFIG_USER_ONLY
> +    TCGv_i32 set_event = tcg_constant_i32(-1);
> +    tcg_gen_st_i32(set_event, tcg_env, offsetof(CPUARMState, event_register));
> +#endif
> +}

This is obviously incorrect as a method of assigning "true" to the "bool" within that union.



r~


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

* Re: [RFC PATCH 27/35] target/arm: wrap event_register in a union
  2026-04-06  0:37   ` Richard Henderson
@ 2026-04-07 10:35     ` Alex Bennée
  2026-04-08  5:41       ` Richard Henderson
  2026-04-08  9:57       ` Peter Maydell
  0 siblings, 2 replies; 74+ messages in thread
From: Alex Bennée @ 2026-04-07 10:35 UTC (permalink / raw)
  To: Richard Henderson; +Cc: qemu-devel

Richard Henderson <richard.henderson@linaro.org> writes:

> On 3/21/26 00:05, Alex Bennée wrote:
>> While the event register is either set or not due to the
>> implementation defined nature of bool types we can't set it directly
>> from TCG code. By wrapping in a union we can alias a 32 bit value to
>> the bool in a future patch.
>> Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
>> ---
>>   target/arm/cpu.h           | 9 +++++++--
>>   hw/intc/armv7m_nvic.c      | 2 +-
>>   target/arm/machine.c       | 4 ++--
>>   target/arm/tcg/m_helper.c  | 4 ++--
>>   target/arm/tcg/op_helper.c | 6 +++---
>>   5 files changed, 15 insertions(+), 10 deletions(-)
>> diff --git a/target/arm/cpu.h b/target/arm/cpu.h
>> index bf6cf74c2e1..9c25b60ae83 100644
>> --- a/target/arm/cpu.h
>> +++ b/target/arm/cpu.h
>> @@ -763,9 +763,14 @@ typedef struct CPUArchState {
>>       /*
>>        * The event register is shared by all ARM profiles (A/R/M),
>>        * so it is stored in the top-level CPU state.
>> -     * WFE/SEV handling is currently implemented only for M-profile.
>> +     *
>> +     * It is treated as a boolean but we need the union so we can set
>> +     * it from TCG.
>>        */
>> -    bool event_register;
>> +    union {
>> +        bool as_bool;
>> +        uint32_t as_uint32;
>> +    } event_register;
>
> What are you attempting here?  This smells like a big-endian bug.
>
> TCG is certainly capable of storing to a bool, via tcg_gen_st8_*.

So the problem I had was I don't know what size bool will be as its up
to each architecture to define the size. I originally had a compile time
assert but that failed. Hence this hack to put something that would
plausibly overlap.

I wonder if there would be a way to use a Generic so tcg_gen_st8_bool
would always map to the right size whichever arch we are on?

>
>
> r~

-- 
Alex Bennée
Virtualisation Tech Lead @ Linaro


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

* Re: [RFC PATCH 27/35] target/arm: wrap event_register in a union
  2026-04-07 10:35     ` Alex Bennée
@ 2026-04-08  5:41       ` Richard Henderson
  2026-04-08  9:57       ` Peter Maydell
  1 sibling, 0 replies; 74+ messages in thread
From: Richard Henderson @ 2026-04-08  5:41 UTC (permalink / raw)
  To: Alex Bennée; +Cc: qemu-devel

On 4/7/26 20:35, Alex Bennée wrote:
> I wonder if there would be a way to use a Generic so tcg_gen_st8_bool
> would always map to the right size whichever arch we are on?

The only outlier for sizeof(bool) that I know of was an ancient x86 Darwin, which is out 
of the support window.  I think there's zero point in planning to support that.


r~


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

* Re: [RFC PATCH 27/35] target/arm: wrap event_register in a union
  2026-04-07 10:35     ` Alex Bennée
  2026-04-08  5:41       ` Richard Henderson
@ 2026-04-08  9:57       ` Peter Maydell
  1 sibling, 0 replies; 74+ messages in thread
From: Peter Maydell @ 2026-04-08  9:57 UTC (permalink / raw)
  To: Alex Bennée; +Cc: Richard Henderson, qemu-devel

On Tue, 7 Apr 2026 at 20:28, Alex Bennée <alex.bennee@linaro.org> wrote:
>
> Richard Henderson <richard.henderson@linaro.org> writes:
>
> > On 3/21/26 00:05, Alex Bennée wrote:
> >> While the event register is either set or not due to the
> >> implementation defined nature of bool types we can't set it directly
> >> from TCG code. By wrapping in a union we can alias a 32 bit value to
> >> the bool in a future patch.
> >> Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
> >> ---
> >>   target/arm/cpu.h           | 9 +++++++--
> >>   hw/intc/armv7m_nvic.c      | 2 +-
> >>   target/arm/machine.c       | 4 ++--
> >>   target/arm/tcg/m_helper.c  | 4 ++--
> >>   target/arm/tcg/op_helper.c | 6 +++---
> >>   5 files changed, 15 insertions(+), 10 deletions(-)
> >> diff --git a/target/arm/cpu.h b/target/arm/cpu.h
> >> index bf6cf74c2e1..9c25b60ae83 100644
> >> --- a/target/arm/cpu.h
> >> +++ b/target/arm/cpu.h
> >> @@ -763,9 +763,14 @@ typedef struct CPUArchState {
> >>       /*
> >>        * The event register is shared by all ARM profiles (A/R/M),
> >>        * so it is stored in the top-level CPU state.
> >> -     * WFE/SEV handling is currently implemented only for M-profile.
> >> +     *
> >> +     * It is treated as a boolean but we need the union so we can set
> >> +     * it from TCG.
> >>        */
> >> -    bool event_register;
> >> +    union {
> >> +        bool as_bool;
> >> +        uint32_t as_uint32;
> >> +    } event_register;
> >
> > What are you attempting here?  This smells like a big-endian bug.
> >
> > TCG is certainly capable of storing to a bool, via tcg_gen_st8_*.
>
> So the problem I had was I don't know what size bool will be as its up
> to each architecture to define the size. I originally had a compile time
> assert but that failed. Hence this hack to put something that would
> plausibly overlap.

If we need to write to it from TCG and we can't just write to a bool,
then we should make this a uint8_t or whatever, rather than messing
about with unions.

-- PMM


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

* Re: [RFC PATCH 24/35] target/arm: remove event_register check from arm_cpu_has_work
  2026-03-20 13:05 ` [RFC PATCH 24/35] target/arm: remove event_register check from arm_cpu_has_work Alex Bennée
@ 2026-04-10  8:47   ` Peter Maydell
  2026-04-10  9:35     ` Alex Bennée
  0 siblings, 1 reply; 74+ messages in thread
From: Peter Maydell @ 2026-04-10  8:47 UTC (permalink / raw)
  To: Alex Bennée
  Cc: qemu-devel, Alexander Graf, qemu-arm, Pedro Barbuda,
	Mohamed Mediouni

On Fri, 20 Mar 2026 at 13:16, Alex Bennée <alex.bennee@linaro.org> wrote:
>
> The generation of events are not indications of work to be done and
> importantly for the case of WFI instructions not a reason to wake up.
> Remove the check.

But an event *is* a reason for WFE to wake up, which is why this
check is here. In particular, the thing that tells accel/tcg
that the CPU should come out of halt (via cpu_handle_halt())
is whether cpu_exec_halt / cpu_has_work returns true. If we
don't check the event register here then another CPU setting
the event register won't cause this one to come out of WFE.

If we want to have WFE and WFI wakeup events to be separated
such that only WFE wakeup events resume a WFE and only
WFI wakeup events resume a WFI then we need to do something
more clever here, so that we track whether we're halted for
WFI, WFE, PSCI-power-off or whatever and our has_work function
can check the right condition. (Side question: are the only
cases where our arm CPUs halt WFE, WFI, power-off, or are
there any others I forgot about?)

Incidentally, looking at the code above it will need fixing
for A-profile anyway, because a CPU in PSCI-power-off should
not be woken up by a WFE event. We get away with doing the
WFE event register check first because M-profile doesn't use
the PSCI powerdown stuff.

thanks
-- PMM


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

* Re: [RFC PATCH 30/35] target/arm: implement global monitor events
  2026-03-20 13:06 ` [RFC PATCH 30/35] target/arm: implement global monitor events Alex Bennée
@ 2026-04-10  9:16   ` Peter Maydell
  0 siblings, 0 replies; 74+ messages in thread
From: Peter Maydell @ 2026-04-10  9:16 UTC (permalink / raw)
  To: Alex Bennée
  Cc: qemu-devel, Alexander Graf, qemu-arm, Pedro Barbuda,
	Mohamed Mediouni

On Fri, 20 Mar 2026 at 13:06, Alex Bennée <alex.bennee@linaro.org> wrote:
>
> Moving from Exclusive to Open Access should generate event stream
> events. Technically a non-exclusive store to any address range covered
> by the global monitor should also trigger such an event but we can
> only detect that after the event by seeing if memory doesn't match
> cpu_exclusive_val when processing the eventual store exclusive.
>
> The CLREX instruction has the same effect as do other operations
> clearing the exclusive state (such as eret).
>
> Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
> ---
>  target/arm/internals.h         | 1 +
>  target/arm/tcg/translate-a64.c | 8 ++++++++
>  2 files changed, 9 insertions(+)
>
> diff --git a/target/arm/internals.h b/target/arm/internals.h
> index 2296ac9cfb6..2e59d58f3d0 100644
> --- a/target/arm/internals.h
> +++ b/target/arm/internals.h
> @@ -690,6 +690,7 @@ void arm_handle_psci_call(ARMCPU *cpu);
>  static inline void arm_clear_exclusive(CPUARMState *env)
>  {
>      env->exclusive_addr = -1;
> +    env->event_register.as_bool = true;
>  }
>
>  /**
> diff --git a/target/arm/tcg/translate-a64.c b/target/arm/tcg/translate-a64.c
> index c25ff9351b4..38a51eb3600 100644
> --- a/target/arm/tcg/translate-a64.c
> +++ b/target/arm/tcg/translate-a64.c
> @@ -2270,6 +2270,7 @@ static bool trans_CHKFEAT(DisasContext *s, arg_CHKFEAT *a)
>  static bool trans_CLREX(DisasContext *s, arg_CLREX *a)
>  {
>      tcg_gen_movi_i64(cpu_exclusive_addr, -1);
> +    gen_event_reg();
>      return true;
>  }
>
> @@ -3336,6 +3337,13 @@ static void gen_store_exclusive(DisasContext *s, int rd, int rt, int rt2,
>      TCGv_i64 tmp, clean_addr;
>      MemOp memop;
>
> +    /*
> +     * All StoreExcl operations will transition the global monitor
> +     * from Exclusive to Open Access and at that point generate an
> +     * Event.
> +     */
> +    gen_event_reg();
> +

This needs to set the event register for all CPUs, not just the
one that does the StoreExcl. See the state machine for the global
monitor in figure B2-5: a "StoreExcl(Marked_address, !n)" (i.e.
some other CPU stores to the address we had an exclusive for)
clears the global monitor for this CPU.

Also, this happens only if the store-exclusive succeeds, so
ideally we should to set the event reg much later in
gen_store_exclusive(). (Because we're allowed to spuriously
wake up WFE for any IMPDEF reason, it's OK to err on the side
of setting the event register when we don't need to, but if
we're taking advantage of that we should say so.)

The IMPDEF latitude to wake up more than we need to is also
why we don't need to try to distinguish "StoreExcl but the
global monitor for this CPU is in the Open Access state".

The important thing we want to check is that our implementation
does the right thing for the "litmus test" example usages in
K11.3.4 which show how WFE and load/store exclusive loops are
supposed to interact. The rough idea is that the lock-acquire
goes to sleep with a WFE, and relies on the lock-release
being a WFE-wakeup event for it. Unfortunately if you look
at K11.3.4.1, the expected "clear the lock" operation is
a STLR operation (a store-release). So we will likely
find that we are causing deadlocks in guest code if we do
not clear the event register in more cases than just store
exclusives.

-- PMM


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

* Re: [RFC PATCH 24/35] target/arm: remove event_register check from arm_cpu_has_work
  2026-04-10  8:47   ` Peter Maydell
@ 2026-04-10  9:35     ` Alex Bennée
  2026-04-10 16:19       ` Alex Bennée
  0 siblings, 1 reply; 74+ messages in thread
From: Alex Bennée @ 2026-04-10  9:35 UTC (permalink / raw)
  To: Peter Maydell
  Cc: qemu-devel, Alexander Graf, qemu-arm, Pedro Barbuda,
	Mohamed Mediouni

Peter Maydell <peter.maydell@linaro.org> writes:

> On Fri, 20 Mar 2026 at 13:16, Alex Bennée <alex.bennee@linaro.org> wrote:
>>
>> The generation of events are not indications of work to be done and
>> importantly for the case of WFI instructions not a reason to wake up.
>> Remove the check.
>
> But an event *is* a reason for WFE to wake up, which is why this
> check is here. In particular, the thing that tells accel/tcg
> that the CPU should come out of halt (via cpu_handle_halt())
> is whether cpu_exec_halt / cpu_has_work returns true. If we
> don't check the event register here then another CPU setting
> the event register won't cause this one to come out of WFE.

So for the same-CPU case we do because we signal cpu_interrupt(cs,
CPU_INTERRUPT_EXITTB) which is enough for has_work to return true but I
can see the failure mode for cross-cpu SEV's when we kick all vCPUs in
the helper would get stuck.

> If we want to have WFE and WFI wakeup events to be separated
> such that only WFE wakeup events resume a WFE and only
> WFI wakeup events resume a WFI then we need to do something
> more clever here, so that we track whether we're halted for
> WFI, WFE, PSCI-power-off or whatever and our has_work function
> can check the right condition.

I guess we can add a cpu->halt_reason? I've already had to add a
cpu->waiting_for_event for arm_wfxt_timer_cb and I guess it would be
better to generalise that.

> (Side question: are the only
> cases where our arm CPUs halt WFE, WFI, power-off, or are
> there any others I forgot about?)

The only others I can find are debug events which all have their own
logic (and we don't have "external" debug events modelled). YIELD is
still a NOP and not really a sleep.

> Incidentally, looking at the code above it will need fixing
> for A-profile anyway, because a CPU in PSCI-power-off should
> not be woken up by a WFE event. We get away with doing the
> WFE event register check first because M-profile doesn't use
> the PSCI powerdown stuff.

Ok, that seals it.

>
> thanks
> -- PMM

-- 
Alex Bennée
Virtualisation Tech Lead @ Linaro


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

* Re: [RFC PATCH 24/35] target/arm: remove event_register check from arm_cpu_has_work
  2026-04-10  9:35     ` Alex Bennée
@ 2026-04-10 16:19       ` Alex Bennée
  0 siblings, 0 replies; 74+ messages in thread
From: Alex Bennée @ 2026-04-10 16:19 UTC (permalink / raw)
  To: Peter Maydell
  Cc: qemu-devel, Alexander Graf, qemu-arm, Pedro Barbuda,
	Mohamed Mediouni

Alex Bennée <alex.bennee@linaro.org> writes:

> Peter Maydell <peter.maydell@linaro.org> writes:
>
>> On Fri, 20 Mar 2026 at 13:16, Alex Bennée <alex.bennee@linaro.org> wrote:
>>>
>>> The generation of events are not indications of work to be done and
>>> importantly for the case of WFI instructions not a reason to wake up.
>>> Remove the check.
>>
>> But an event *is* a reason for WFE to wake up, which is why this
>> check is here. In particular, the thing that tells accel/tcg
>> that the CPU should come out of halt (via cpu_handle_halt())
>> is whether cpu_exec_halt / cpu_has_work returns true. If we
>> don't check the event register here then another CPU setting
>> the event register won't cause this one to come out of WFE.
>
> So for the same-CPU case we do because we signal cpu_interrupt(cs,
> CPU_INTERRUPT_EXITTB) which is enough for has_work to return true but I
> can see the failure mode for cross-cpu SEV's when we kick all vCPUs in
> the helper would get stuck.
>
>> If we want to have WFE and WFI wakeup events to be separated
>> such that only WFE wakeup events resume a WFE and only
>> WFI wakeup events resume a WFI then we need to do something
>> more clever here, so that we track whether we're halted for
>> WFI, WFE, PSCI-power-off or whatever and our has_work function
>> can check the right condition.
>
> I guess we can add a cpu->halt_reason? I've already had to add a
> cpu->waiting_for_event for arm_wfxt_timer_cb and I guess it would be
> better to generalise that.
>
>> (Side question: are the only
>> cases where our arm CPUs halt WFE, WFI, power-off, or are
>> there any others I forgot about?)
>
> The only others I can find are debug events which all have their own
> logic (and we don't have "external" debug events modelled). YIELD is
> still a NOP and not really a sleep.
>
>> Incidentally, looking at the code above it will need fixing
>> for A-profile anyway, because a CPU in PSCI-power-off should
>> not be woken up by a WFE event. We get away with doing the
>> WFE event register check first because M-profile doesn't use
>> the PSCI powerdown stuff.
>
> Ok, that seals it.

I'm thinking something like this:

--8<---------------cut here---------------start------------->8---
modified    target/arm/cpu.h
@@ -257,6 +257,19 @@ typedef enum ARMFPStatusFlavour {
 } ARMFPStatusFlavour;
 #define FPST_COUNT  10
 
+/**
+ * ARMHaltReason - the reason we have entered halt state
+ *
+ * To be able to correctly wake up via arm_cpu_has_work() we need to
+ * track the reason we went to sleep.
+ */
+typedef enum {
+    NOT_HALTED = 0,
+    HALT_PSCI,
+    HALT_WFI,
+    HALT_WFE
+} ARMHaltReason;
+
 typedef struct CPUArchState {
     /* Regs for current mode.  */
     uint32_t regs[16];
@@ -760,6 +773,9 @@ typedef struct CPUArchState {
     /* Optional fault info across tlb lookup. */
     ARMMMUFaultInfo *tlb_fi;
 
+    /* Reason the CPU is halted */
+    ARMHaltReason halt_reason;
+
     /*
      * The event register is shared by all ARM profiles (A/R/M),
      * so it is stored in the top-level CPU state.
modified    target/arm/arm-powerctl.c
@@ -78,6 +78,7 @@ static void arm_set_cpu_on_async_work(CPUState *target_cpu_state,
 
     /* Finally set the power status */
     assert(bql_locked());
+    target_cpu->env.halt_reason = NOT_HALTED;
     target_cpu->power_state = PSCI_ON;
 }
 
@@ -240,6 +241,7 @@ static void arm_set_cpu_off_async_work(CPUState *target_cpu_state,
 
     assert(bql_locked());
     target_cpu->power_state = PSCI_OFF;
+    target_cpu->env.halt_reason = HALT_PSCI;
     target_cpu_state->halted = 1;
     target_cpu_state->exception_index = EXCP_HLT;
 }
modified    target/arm/cpu.c
@@ -144,18 +144,36 @@ static bool arm_cpu_has_work(CPUState *cs)
 {
     ARMCPU *cpu = ARM_CPU(cs);
 
-    if (arm_feature(&cpu->env, ARM_FEATURE_M)) {
-        if (cpu->env.event_register) {
-            return true;
-        }
+    /*
+     * Only another PSCI call can wake the CPU up in which case the
+     * power_state would be set by reset.
+     */
+    if (cpu->power_state == PSCI_OFF) {
+        g_assert(cpu->env.halt_reason == HALT_PSCI);
+        return false;
+    }
+
+    /*
+     * A wake-up event should only wake us if we are halted on a WFE
+     */
+    if (cpu->env.halt_reason == HALT_WFE && cpu->env.event_register) {
+        cpu->env.halt_reason = NOT_HALTED;
+        return true;
+    }
+
+    /*
+     * Otherwise pretty much any IRQ would wake us up
+     */
+    if (cpu_test_interrupt(cs,
+                           CPU_INTERRUPT_FIQ | CPU_INTERRUPT_HARD
+                           | CPU_INTERRUPT_NMI | CPU_INTERRUPT_VINMI | CPU_INTERRUPT_VFNMI
+                           | CPU_INTERRUPT_VFIQ | CPU_INTERRUPT_VIRQ | CPU_INTERRUPT_VSERR
+                           | CPU_INTERRUPT_EXITTB)) {
+        cpu->env.halt_reason = NOT_HALTED;
+        return true;
     }
 
-    return (cpu->power_state != PSCI_OFF)
-        && cpu_test_interrupt(cs,
-               CPU_INTERRUPT_FIQ | CPU_INTERRUPT_HARD
-               | CPU_INTERRUPT_NMI | CPU_INTERRUPT_VINMI | CPU_INTERRUPT_VFNMI
-               | CPU_INTERRUPT_VFIQ | CPU_INTERRUPT_VIRQ | CPU_INTERRUPT_VSERR
-               | CPU_INTERRUPT_EXITTB);
+    return false;
 }
 #endif /* !CONFIG_USER_ONLY */
 
modified    target/arm/tcg/op_helper.c
@@ -403,6 +403,7 @@ void HELPER(wfi)(CPUARMState *env, uint32_t insn_len)
                         target_el);
     }
 
+    env->halt_reason = HALT_WFI;
     cs->exception_index = EXCP_HLT;
     cs->halted = 1;
     cpu_loop_exit(cs);
@@ -464,6 +465,7 @@ void HELPER(wfit)(CPUARMState *env, uint32_t rd)
     } else {
         timer_mod(cpu->wfxt_timer, nexttick);
     }
+    env->halt_reason = HALT_WFI;
     cs->exception_index = EXCP_HLT;
     cs->halted = 1;
     cpu_loop_exit(cs);
@@ -508,6 +510,7 @@ void HELPER(wfe)(CPUARMState *env)
             return;
         }
 
+        env->halt_reason = HALT_WFE;
         cs->exception_index = EXCP_HLT;
         cs->halted = 1;
         cpu_loop_exit(cs);
--8<---------------cut here---------------end--------------->8---


>
>>
>> thanks
>> -- PMM

-- 
Alex Bennée
Virtualisation Tech Lead @ Linaro


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

end of thread, other threads:[~2026-04-10 16:20 UTC | newest]

Thread overview: 74+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-03-20 13:05 [RFC PATCH 00/35] target/arm: fully model WFxT instructions for A-profile Alex Bennée
2026-03-20 13:05 ` [RFC PATCH 01/35] target/arm: migrate basic syndrome helpers to registerfields Alex Bennée
2026-04-01  5:36   ` Richard Henderson
2026-03-20 13:05 ` [RFC PATCH 02/35] target/arm: migrate system/cp trap syndromes " Alex Bennée
2026-04-01  5:39   ` Richard Henderson
2026-03-20 13:05 ` [RFC PATCH 03/35] target/arm: migrate FP/SIMD " Alex Bennée
2026-04-01  5:43   ` Richard Henderson
2026-04-01 12:50     ` Alex Bennée
2026-04-01 15:48       ` Peter Maydell
2026-04-01 17:54       ` Pierrick Bouvier
2026-03-20 13:05 ` [RFC PATCH 04/35] target/arm: migrate eret " Alex Bennée
2026-04-05 23:21   ` Richard Henderson
2026-03-20 13:05 ` [RFC PATCH 05/35] target/arm: migrate SME " Alex Bennée
2026-04-05 23:22   ` Richard Henderson
2026-03-20 13:05 ` [RFC PATCH 06/35] target/arm: migrate PAC " Alex Bennée
2026-04-05 23:23   ` Richard Henderson
2026-03-20 13:05 ` [RFC PATCH 07/35] target/arm: migrate BTI " Alex Bennée
2026-04-05 23:28   ` Richard Henderson
2026-03-20 13:05 ` [RFC PATCH 08/35] target/arm: migrate BXJ " Alex Bennée
2026-04-05 23:29   ` Richard Henderson
2026-03-20 13:05 ` [RFC PATCH 09/35] target/arm: migrate Granule Protection traps " Alex Bennée
2026-04-05 23:30   ` Richard Henderson
2026-03-20 13:05 ` [RFC PATCH 10/35] target/arm: migrate fault syndromes " Alex Bennée
2026-04-05 23:32   ` Richard Henderson
2026-03-20 13:05 ` [RFC PATCH 11/35] target/arm: migrate debug " Alex Bennée
2026-04-05 23:37   ` Richard Henderson
2026-03-20 13:05 ` [RFC PATCH 12/35] target/arm: migrate wfx " Alex Bennée
2026-04-05 23:41   ` Richard Henderson
2026-03-20 13:05 ` [RFC PATCH 13/35] target/arm: migrate gcs " Alex Bennée
2026-04-05 23:43   ` Richard Henderson
2026-03-20 13:05 ` [RFC PATCH 14/35] target/arm: migrate memory op " Alex Bennée
2026-04-05 23:44   ` Richard Henderson
2026-03-20 13:05 ` [RFC PATCH 15/35] target/arm: migrate check_hcr_el2_trap to use syndrome helper Alex Bennée
2026-04-06  0:01   ` Richard Henderson
2026-03-20 13:05 ` [RFC PATCH 16/35] target/arm: use syndrome helpers in arm_cpu_do_interrupt_aarch32_hyp Alex Bennée
2026-04-06  0:06   ` Richard Henderson
2026-03-20 13:05 ` [RFC PATCH 17/35] target/arm: use syndrome helpers to set SAME_EL EC bit Alex Bennée
2026-04-06  0:07   ` Richard Henderson
2026-03-20 13:05 ` [RFC PATCH 18/35] target/arm: make whpx use syndrome helpers for decode Alex Bennée
2026-04-06  0:08   ` Richard Henderson
2026-03-20 13:05 ` [RFC PATCH 19/35] target/arm: make hvf " Alex Bennée
2026-04-06  0:08   ` Richard Henderson
2026-03-20 13:05 ` [RFC PATCH 20/35] target/arm: use syndrome helpers in merge_syn_data_abort Alex Bennée
2026-04-06  0:15   ` Richard Henderson
2026-03-20 13:05 ` [RFC PATCH 21/35] target/arm: use syndrome helpers to query VNCR bit Alex Bennée
2026-04-06  0:17   ` Richard Henderson
2026-03-20 13:05 ` [RFC PATCH 22/35] target/arm: remove old syndrome defines Alex Bennée
2026-04-06  0:17   ` Richard Henderson
2026-03-20 13:05 ` [RFC PATCH 23/35] target/arm: report register in WFIT syndromes Alex Bennée
2026-04-06  0:24   ` Richard Henderson
2026-03-20 13:05 ` [RFC PATCH 24/35] target/arm: remove event_register check from arm_cpu_has_work Alex Bennée
2026-04-10  8:47   ` Peter Maydell
2026-04-10  9:35     ` Alex Bennée
2026-04-10 16:19       ` Alex Bennée
2026-03-20 13:05 ` [RFC PATCH 25/35] target/arm: redefine event stream fields Alex Bennée
2026-04-06  0:30   ` Richard Henderson
2026-03-20 13:05 ` [RFC PATCH 26/35] target/arm: add gt_calc_next_event_stream Alex Bennée
2026-04-06  0:34   ` Richard Henderson
2026-03-20 13:05 ` [RFC PATCH 27/35] target/arm: wrap event_register in a union Alex Bennée
2026-04-06  0:37   ` Richard Henderson
2026-04-07 10:35     ` Alex Bennée
2026-04-08  5:41       ` Richard Henderson
2026-04-08  9:57       ` Peter Maydell
2026-03-20 13:05 ` [RFC PATCH 28/35] target/arm: ensure aarch64 DISAS_WFE will exit Alex Bennée
2026-04-06  3:00   ` Richard Henderson
2026-03-20 13:06 ` [RFC PATCH 29/35] target/arm: implements SEV/SEVL for all modes Alex Bennée
2026-04-06  3:22   ` Richard Henderson
2026-03-20 13:06 ` [RFC PATCH 30/35] target/arm: implement global monitor events Alex Bennée
2026-04-10  9:16   ` Peter Maydell
2026-03-20 13:06 ` [RFC PATCH 31/35] target/arm: enable event stream on WFE instructions Alex Bennée
2026-03-20 13:06 ` [RFC PATCH 32/35] target/arm: implement WFET Alex Bennée
2026-03-20 13:06 ` [RFC PATCH 33/35] tests/tcg: split stage 1 between devices and RAM Alex Bennée
2026-03-20 13:06 ` [RFC PATCH 34/35] tests/tcg: create a mini-gic3 library Alex Bennée
2026-03-20 13:06 ` [RFC PATCH 35/35] tests/tcg: add basic test for aarch64 wf[ie][t] insns Alex Bennée

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.