* [PATCH v2 00/31] target/arm: fully model WFxT instructions for A-profile
@ 2026-04-22 10:10 Alex Bennée
2026-04-22 10:10 ` [PATCH v2 01/31] target/arm: migrate basic syndrome helpers to registerfields Alex Bennée
` (31 more replies)
0 siblings, 32 replies; 33+ messages in thread
From: Alex Bennée @ 2026-04-22 10:10 UTC (permalink / raw)
To: qemu-devel
Cc: Alexander Graf, qemu-arm, Peter Maydell, Paolo Bonzini,
Mohamed Mediouni, kvm, Pedro Barbuda, 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 an RFC 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.
v2
- I've kept the tests separate, see:
Message-ID: <20260417164328.1009132-1-alex.bennee@linaro.org>
Date: Fri, 17 Apr 2026 17:43:20 +0100
Subject: [PATCH 0/7] tests/tcg: more capabilities for aarch64-softmmu tests
From: =?UTF-8?q?Alex=20Benn=C3=A9e?= <alex.bennee@linaro.org>
- tweaks to global monitor behaviour
- STLR/STL will also trigger events to avoid deadlocks
- see under the --- in the patches for details
Alex.
Alex Bennée (31):
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: teach arm_cpu_has_work about halting reasons
target/arm: redefine event stream fields
target/arm: ensure aarch64 DISAS_WFE will exit
target/arm: implements SEV/SEVL for all modes
target/arm: hoist event broadcast code into a helper
target/arm: implement global monitor events
target/arm: enable event stream on WFE instructions
target/arm: implement WFET
target/arm/cpu.h | 27 ++
target/arm/internals.h | 31 +-
target/arm/syndrome.h | 595 +++++++++++++++++++++++++++------
target/arm/tcg/helper-defs.h | 3 +-
target/arm/tcg/translate.h | 32 ++
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/arm-powerctl.c | 4 +-
target/arm/cpu.c | 53 ++-
target/arm/helper.c | 12 +-
target/arm/hvf/hvf.c | 14 +-
target/arm/kvm.c | 5 +-
target/arm/machine.c | 2 +-
target/arm/tcg/debug.c | 2 +-
target/arm/tcg/op_helper.c | 216 ++++++++++--
target/arm/tcg/tlb_helper.c | 6 +-
target/arm/tcg/translate-a64.c | 58 +++-
target/arm/tcg/translate.c | 33 +-
target/arm/tcg/vfp_helper.c | 5 +-
target/arm/whpx/whpx-all.c | 13 +-
22 files changed, 929 insertions(+), 200 deletions(-)
--
2.47.3
^ permalink raw reply [flat|nested] 33+ messages in thread
* [PATCH v2 01/31] target/arm: migrate basic syndrome helpers to registerfields
2026-04-22 10:10 [PATCH v2 00/31] target/arm: fully model WFxT instructions for A-profile Alex Bennée
@ 2026-04-22 10:10 ` Alex Bennée
2026-04-22 10:10 ` [PATCH v2 02/31] target/arm: migrate system/cp trap syndromes " Alex Bennée
` (30 subsequent siblings)
31 siblings, 0 replies; 33+ messages in thread
From: Alex Bennée @ 2026-04-22 10:10 UTC (permalink / raw)
To: qemu-devel
Cc: Alexander Graf, qemu-arm, Peter Maydell, Paolo Bonzini,
Mohamed Mediouni, kvm, Pedro Barbuda, Alex Bennée,
Richard Henderson
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.
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
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] 33+ messages in thread
* [PATCH v2 02/31] target/arm: migrate system/cp trap syndromes to registerfields
2026-04-22 10:10 [PATCH v2 00/31] target/arm: fully model WFxT instructions for A-profile Alex Bennée
2026-04-22 10:10 ` [PATCH v2 01/31] target/arm: migrate basic syndrome helpers to registerfields Alex Bennée
@ 2026-04-22 10:10 ` Alex Bennée
2026-04-22 10:10 ` [PATCH v2 03/31] target/arm: migrate FP/SIMD " Alex Bennée
` (29 subsequent siblings)
31 siblings, 0 replies; 33+ messages in thread
From: Alex Bennée @ 2026-04-22 10:10 UTC (permalink / raw)
To: qemu-devel
Cc: Alexander Graf, qemu-arm, Peter Maydell, Paolo Bonzini,
Mohamed Mediouni, kvm, Pedro Barbuda, Alex Bennée,
Richard Henderson
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.
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
---
v2
- use !is_16bit directly
---
target/arm/syndrome.h | 124 ++++++++++++++++++++++++++++++++++--------
1 file changed, 102 insertions(+), 22 deletions(-)
diff --git a/target/arm/syndrome.h b/target/arm/syndrome.h
index 517fb2368bc..29462aa103c 100644
--- a/target/arm/syndrome.h
+++ b/target/arm/syndrome.h
@@ -78,7 +78,7 @@ enum arm_exception_class {
/* 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, IL, 25, 1) /* IL=1 for 32 bit instructions */
FIELD(SYNDROME, ISS, 0, 25)
typedef enum {
@@ -172,7 +172,7 @@ static inline uint32_t syn_aa64_smc(uint32_t imm16)
static inline uint32_t syn_aa32_svc(uint32_t imm16, bool is_16bit)
{
uint32_t res = syn_set_ec(0, EC_AA32_SVC);
- res = FIELD_DP32(res, SYNDROME, IL, is_16bit ? 0 : 1);
+ res = FIELD_DP32(res, SYNDROME, IL, !is_16bit);
res = FIELD_DP32(res, ISS_IMM16, IMM16, imm16);
return res;
}
@@ -203,58 +203,138 @@ static inline uint32_t syn_aa64_bkpt(uint32_t imm16)
static inline uint32_t syn_aa32_bkpt(uint32_t imm16, bool is_16bit)
{
uint32_t res = syn_set_ec(0, EC_AA32_BKPT);
- res = FIELD_DP32(res, SYNDROME, IL, is_16bit ? 0 : 1);
+ res = FIELD_DP32(res, SYNDROME, IL, !is_16bit);
res = FIELD_DP32(res, ISS_IMM16, IMM16, imm16);
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);
+
+ 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);
+
+ 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);
+
+ 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);
+
+ 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] 33+ messages in thread
* [PATCH v2 03/31] target/arm: migrate FP/SIMD trap syndromes to registerfields
2026-04-22 10:10 [PATCH v2 00/31] target/arm: fully model WFxT instructions for A-profile Alex Bennée
2026-04-22 10:10 ` [PATCH v2 01/31] target/arm: migrate basic syndrome helpers to registerfields Alex Bennée
2026-04-22 10:10 ` [PATCH v2 02/31] target/arm: migrate system/cp trap syndromes " Alex Bennée
@ 2026-04-22 10:10 ` Alex Bennée
2026-04-22 10:10 ` [PATCH v2 04/31] target/arm: migrate eret " Alex Bennée
` (28 subsequent siblings)
31 siblings, 0 replies; 33+ messages in thread
From: Alex Bennée @ 2026-04-22 10:10 UTC (permalink / raw)
To: qemu-devel
Cc: Alexander Graf, qemu-arm, Peter Maydell, Paolo Bonzini,
Mohamed Mediouni, kvm, Pedro Barbuda, Alex Bennée,
Richard Henderson
The syn_simd_access trap was never used so remove it. We should only
see the COPROC encoding on v7 architectures.
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
---
v2
- use !is16_bit directly
---
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 29462aa103c..72051443d59 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);
-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] 33+ messages in thread
* [PATCH v2 04/31] target/arm: migrate eret trap syndromes to registerfields
2026-04-22 10:10 [PATCH v2 00/31] target/arm: fully model WFxT instructions for A-profile Alex Bennée
` (2 preceding siblings ...)
2026-04-22 10:10 ` [PATCH v2 03/31] target/arm: migrate FP/SIMD " Alex Bennée
@ 2026-04-22 10:10 ` Alex Bennée
2026-04-22 10:10 ` [PATCH v2 05/31] target/arm: migrate SME " Alex Bennée
` (27 subsequent siblings)
31 siblings, 0 replies; 33+ messages in thread
From: Alex Bennée @ 2026-04-22 10:10 UTC (permalink / raw)
To: qemu-devel
Cc: Alexander Graf, qemu-arm, Peter Maydell, Paolo Bonzini,
Mohamed Mediouni, kvm, Pedro Barbuda, Alex Bennée,
Richard Henderson
For simplicity keep the OP as a two bit field rather than the two
interlinked fields in the docs (ERET/ERETA).
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
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 72051443d59..63c8e66ea91 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] 33+ messages in thread
* [PATCH v2 05/31] target/arm: migrate SME trap syndromes to registerfields
2026-04-22 10:10 [PATCH v2 00/31] target/arm: fully model WFxT instructions for A-profile Alex Bennée
` (3 preceding siblings ...)
2026-04-22 10:10 ` [PATCH v2 04/31] target/arm: migrate eret " Alex Bennée
@ 2026-04-22 10:10 ` Alex Bennée
2026-04-22 10:10 ` [PATCH v2 06/31] target/arm: migrate PAC " Alex Bennée
` (26 subsequent siblings)
31 siblings, 0 replies; 33+ messages in thread
From: Alex Bennée @ 2026-04-22 10:10 UTC (permalink / raw)
To: qemu-devel
Cc: Alexander Graf, qemu-arm, Peter Maydell, Paolo Bonzini,
Mohamed Mediouni, kvm, Pedro Barbuda, Alex Bennée,
Richard Henderson
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
---
v2
- use !is_16bit directly
---
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 63c8e66ea91..61053475984 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);
+ 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] 33+ messages in thread
* [PATCH v2 06/31] target/arm: migrate PAC trap syndromes to registerfields
2026-04-22 10:10 [PATCH v2 00/31] target/arm: fully model WFxT instructions for A-profile Alex Bennée
` (4 preceding siblings ...)
2026-04-22 10:10 ` [PATCH v2 05/31] target/arm: migrate SME " Alex Bennée
@ 2026-04-22 10:10 ` Alex Bennée
2026-04-22 10:10 ` [PATCH v2 07/31] target/arm: migrate BTI " Alex Bennée
` (25 subsequent siblings)
31 siblings, 0 replies; 33+ messages in thread
From: Alex Bennée @ 2026-04-22 10:10 UTC (permalink / raw)
To: qemu-devel
Cc: Alexander Graf, qemu-arm, Peter Maydell, Paolo Bonzini,
Mohamed Mediouni, kvm, Pedro Barbuda, Alex Bennée,
Richard Henderson
syn_pactrap is fairly simple as the ISS is all RES0.
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
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 61053475984..fd8639d4f07 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] 33+ messages in thread
* [PATCH v2 07/31] target/arm: migrate BTI trap syndromes to registerfields
2026-04-22 10:10 [PATCH v2 00/31] target/arm: fully model WFxT instructions for A-profile Alex Bennée
` (5 preceding siblings ...)
2026-04-22 10:10 ` [PATCH v2 06/31] target/arm: migrate PAC " Alex Bennée
@ 2026-04-22 10:10 ` Alex Bennée
2026-04-22 10:10 ` [PATCH v2 08/31] target/arm: migrate BXJ " Alex Bennée
` (24 subsequent siblings)
31 siblings, 0 replies; 33+ messages in thread
From: Alex Bennée @ 2026-04-22 10:10 UTC (permalink / raw)
To: qemu-devel
Cc: Alexander Graf, qemu-arm, Peter Maydell, Paolo Bonzini,
Mohamed Mediouni, kvm, Pedro Barbuda, Alex Bennée,
Richard Henderson
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
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 fd8639d4f07..52a6745cb23 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] 33+ messages in thread
* [PATCH v2 08/31] target/arm: migrate BXJ trap syndromes to registerfields
2026-04-22 10:10 [PATCH v2 00/31] target/arm: fully model WFxT instructions for A-profile Alex Bennée
` (6 preceding siblings ...)
2026-04-22 10:10 ` [PATCH v2 07/31] target/arm: migrate BTI " Alex Bennée
@ 2026-04-22 10:10 ` Alex Bennée
2026-04-22 10:10 ` [PATCH v2 09/31] target/arm: migrate Granule Protection traps " Alex Bennée
` (23 subsequent siblings)
31 siblings, 0 replies; 33+ messages in thread
From: Alex Bennée @ 2026-04-22 10:10 UTC (permalink / raw)
To: qemu-devel
Cc: Alexander Graf, qemu-arm, Peter Maydell, Paolo Bonzini,
Mohamed Mediouni, kvm, Pedro Barbuda, Alex Bennée,
Richard Henderson
This is an Armv7 specific syndrome for chips with Jazelle
functionality.
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
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 52a6745cb23..6fcf0ac7572 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] 33+ messages in thread
* [PATCH v2 09/31] target/arm: migrate Granule Protection traps to registerfields
2026-04-22 10:10 [PATCH v2 00/31] target/arm: fully model WFxT instructions for A-profile Alex Bennée
` (7 preceding siblings ...)
2026-04-22 10:10 ` [PATCH v2 08/31] target/arm: migrate BXJ " Alex Bennée
@ 2026-04-22 10:10 ` Alex Bennée
2026-04-22 10:10 ` [PATCH v2 10/31] target/arm: migrate fault syndromes " Alex Bennée
` (22 subsequent siblings)
31 siblings, 0 replies; 33+ messages in thread
From: Alex Bennée @ 2026-04-22 10:10 UTC (permalink / raw)
To: qemu-devel
Cc: Alexander Graf, qemu-arm, Peter Maydell, Paolo Bonzini,
Mohamed Mediouni, kvm, Pedro Barbuda, Alex Bennée,
Richard Henderson
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
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 6fcf0ac7572..bc65106c61a 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] 33+ messages in thread
* [PATCH v2 10/31] target/arm: migrate fault syndromes to registerfields
2026-04-22 10:10 [PATCH v2 00/31] target/arm: fully model WFxT instructions for A-profile Alex Bennée
` (8 preceding siblings ...)
2026-04-22 10:10 ` [PATCH v2 09/31] target/arm: migrate Granule Protection traps " Alex Bennée
@ 2026-04-22 10:10 ` Alex Bennée
2026-04-22 10:10 ` [PATCH v2 11/31] target/arm: migrate debug " Alex Bennée
` (21 subsequent siblings)
31 siblings, 0 replies; 33+ messages in thread
From: Alex Bennée @ 2026-04-22 10:10 UTC (permalink / raw)
To: qemu-devel
Cc: Alexander Graf, qemu-arm, Peter Maydell, Paolo Bonzini,
Mohamed Mediouni, kvm, Pedro Barbuda, Alex Bennée,
Richard Henderson
Migrate syn_insn_abort and syn_data_abort_* to the registerfields API.
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
---
v2
- use !is_16bit directly
---
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 bc65106c61a..2031b3704fb 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);
+
+ 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] 33+ messages in thread
* [PATCH v2 11/31] target/arm: migrate debug syndromes to registerfields
2026-04-22 10:10 [PATCH v2 00/31] target/arm: fully model WFxT instructions for A-profile Alex Bennée
` (9 preceding siblings ...)
2026-04-22 10:10 ` [PATCH v2 10/31] target/arm: migrate fault syndromes " Alex Bennée
@ 2026-04-22 10:10 ` Alex Bennée
2026-04-22 10:10 ` [PATCH v2 12/31] target/arm: migrate wfx " Alex Bennée
` (20 subsequent siblings)
31 siblings, 0 replies; 33+ messages in thread
From: Alex Bennée @ 2026-04-22 10:10 UTC (permalink / raw)
To: qemu-devel
Cc: Alexander Graf, qemu-arm, Peter Maydell, Paolo Bonzini,
Mohamed Mediouni, kvm, Pedro Barbuda, Alex Bennée,
Richard Henderson
Migrate syn_swstep, syn_watchpoint and syn_breakpoint to the
registerfields API.
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
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 2031b3704fb..2ad6b97aea5 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] 33+ messages in thread
* [PATCH v2 12/31] target/arm: migrate wfx syndromes to registerfields
2026-04-22 10:10 [PATCH v2 00/31] target/arm: fully model WFxT instructions for A-profile Alex Bennée
` (10 preceding siblings ...)
2026-04-22 10:10 ` [PATCH v2 11/31] target/arm: migrate debug " Alex Bennée
@ 2026-04-22 10:10 ` Alex Bennée
2026-04-22 10:10 ` [PATCH v2 13/31] target/arm: migrate gcs " Alex Bennée
` (19 subsequent siblings)
31 siblings, 0 replies; 33+ messages in thread
From: Alex Bennée @ 2026-04-22 10:10 UTC (permalink / raw)
To: qemu-devel
Cc: Alexander Graf, qemu-arm, Peter Maydell, Paolo Bonzini,
Mohamed Mediouni, kvm, Pedro Barbuda, Alex Bennée,
Richard Henderson
This will help later when we expand the fields we report.
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
---
v2
- use !is_16bit directly
---
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 2ad6b97aea5..65d0de63a83 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);
+
+ 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] 33+ messages in thread
* [PATCH v2 13/31] target/arm: migrate gcs syndromes to registerfields
2026-04-22 10:10 [PATCH v2 00/31] target/arm: fully model WFxT instructions for A-profile Alex Bennée
` (11 preceding siblings ...)
2026-04-22 10:10 ` [PATCH v2 12/31] target/arm: migrate wfx " Alex Bennée
@ 2026-04-22 10:10 ` Alex Bennée
2026-04-22 10:10 ` [PATCH v2 14/31] target/arm: migrate memory op " Alex Bennée
` (18 subsequent siblings)
31 siblings, 0 replies; 33+ messages in thread
From: Alex Bennée @ 2026-04-22 10:10 UTC (permalink / raw)
To: qemu-devel
Cc: Alexander Graf, qemu-arm, Peter Maydell, Paolo Bonzini,
Mohamed Mediouni, kvm, Pedro Barbuda, Alex Bennée,
Richard Henderson
Tweak arg names to make it clear raddr is the data address register
number.
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
---
v2
- rename ra->raddr to document things.
---
target/arm/syndrome.h | 39 +++++++++++++++++++++++++++++++++------
1 file changed, 33 insertions(+), 6 deletions(-)
diff --git a/target/arm/syndrome.h b/target/arm/syndrome.h
index 65d0de63a83..7ff8c30e2bb 100644
--- a/target/arm/syndrome.h
+++ b/target/arm/syndrome.h
@@ -690,21 +690,48 @@ 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)
+static inline uint32_t syn_gcs_gcsstr(int raddr, 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);
+ res = FIELD_DP32(res, GCS_ISS, RADDR, raddr);
+ 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] 33+ messages in thread
* [PATCH v2 14/31] target/arm: migrate memory op syndromes to registerfields
2026-04-22 10:10 [PATCH v2 00/31] target/arm: fully model WFxT instructions for A-profile Alex Bennée
` (12 preceding siblings ...)
2026-04-22 10:10 ` [PATCH v2 13/31] target/arm: migrate gcs " Alex Bennée
@ 2026-04-22 10:10 ` Alex Bennée
2026-04-22 10:10 ` [PATCH v2 15/31] target/arm: migrate check_hcr_el2_trap to use syndrome helper Alex Bennée
` (17 subsequent siblings)
31 siblings, 0 replies; 33+ messages in thread
From: Alex Bennée @ 2026-04-22 10:10 UTC (permalink / raw)
To: qemu-devel
Cc: Alexander Graf, qemu-arm, Peter Maydell, Paolo Bonzini,
Mohamed Mediouni, kvm, Pedro Barbuda, Alex Bennée,
Richard Henderson
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
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 7ff8c30e2bb..841fd3292b8 100644
--- a/target/arm/syndrome.h
+++ b/target/arm/syndrome.h
@@ -742,14 +742,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] 33+ messages in thread
* [PATCH v2 15/31] target/arm: migrate check_hcr_el2_trap to use syndrome helper
2026-04-22 10:10 [PATCH v2 00/31] target/arm: fully model WFxT instructions for A-profile Alex Bennée
` (13 preceding siblings ...)
2026-04-22 10:10 ` [PATCH v2 14/31] target/arm: migrate memory op " Alex Bennée
@ 2026-04-22 10:10 ` Alex Bennée
2026-04-22 10:10 ` [PATCH v2 16/31] target/arm: use syndrome helpers in arm_cpu_do_interrupt_aarch32_hyp Alex Bennée
` (16 subsequent siblings)
31 siblings, 0 replies; 33+ messages in thread
From: Alex Bennée @ 2026-04-22 10:10 UTC (permalink / raw)
To: qemu-devel
Cc: Alexander Graf, qemu-arm, Peter Maydell, Paolo Bonzini,
Mohamed Mediouni, kvm, Pedro Barbuda, Alex Bennée,
Richard Henderson
It shares the same COPROC_ISS encoding as the other CP traps although
not all the fields are used.
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
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 841fd3292b8..53137394e28 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] 33+ messages in thread
* [PATCH v2 16/31] target/arm: use syndrome helpers in arm_cpu_do_interrupt_aarch32_hyp
2026-04-22 10:10 [PATCH v2 00/31] target/arm: fully model WFxT instructions for A-profile Alex Bennée
` (14 preceding siblings ...)
2026-04-22 10:10 ` [PATCH v2 15/31] target/arm: migrate check_hcr_el2_trap to use syndrome helper Alex Bennée
@ 2026-04-22 10:10 ` Alex Bennée
2026-04-22 10:10 ` [PATCH v2 17/31] target/arm: use syndrome helpers to set SAME_EL EC bit Alex Bennée
` (15 subsequent siblings)
31 siblings, 0 replies; 33+ messages in thread
From: Alex Bennée @ 2026-04-22 10:10 UTC (permalink / raw)
To: qemu-devel
Cc: Alexander Graf, qemu-arm, Peter Maydell, Paolo Bonzini,
Mohamed Mediouni, kvm, Pedro Barbuda, Alex Bennée,
Richard Henderson
One more step towards dropping the old #defines.
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
---
v2
- drop excess brackets
---
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..40dd070d2c1 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] 33+ messages in thread
* [PATCH v2 17/31] target/arm: use syndrome helpers to set SAME_EL EC bit
2026-04-22 10:10 [PATCH v2 00/31] target/arm: fully model WFxT instructions for A-profile Alex Bennée
` (15 preceding siblings ...)
2026-04-22 10:10 ` [PATCH v2 16/31] target/arm: use syndrome helpers in arm_cpu_do_interrupt_aarch32_hyp Alex Bennée
@ 2026-04-22 10:10 ` Alex Bennée
2026-04-22 10:10 ` [PATCH v2 18/31] target/arm: make whpx use syndrome helpers for decode Alex Bennée
` (14 subsequent siblings)
31 siblings, 0 replies; 33+ messages in thread
From: Alex Bennée @ 2026-04-22 10:10 UTC (permalink / raw)
To: qemu-devel
Cc: Alexander Graf, qemu-arm, Peter Maydell, Paolo Bonzini,
Mohamed Mediouni, kvm, Pedro Barbuda, Alex Bennée,
Richard Henderson
This removes the last use of ARM_EL_EC_SHIFT.
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
---
v2
- drop ARM_EL_EC_SHIFT at this point
---
target/arm/syndrome.h | 1 -
target/arm/tcg/debug.c | 2 +-
2 files changed, 1 insertion(+), 2 deletions(-)
diff --git a/target/arm/syndrome.h b/target/arm/syndrome.h
index 53137394e28..d4dfab8cd15 100644
--- a/target/arm/syndrome.h
+++ b/target/arm/syndrome.h
@@ -107,7 +107,6 @@ typedef enum {
} 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)
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] 33+ messages in thread
* [PATCH v2 18/31] target/arm: make whpx use syndrome helpers for decode
2026-04-22 10:10 [PATCH v2 00/31] target/arm: fully model WFxT instructions for A-profile Alex Bennée
` (16 preceding siblings ...)
2026-04-22 10:10 ` [PATCH v2 17/31] target/arm: use syndrome helpers to set SAME_EL EC bit Alex Bennée
@ 2026-04-22 10:10 ` Alex Bennée
2026-04-22 10:10 ` [PATCH v2 19/31] target/arm: make hvf " Alex Bennée
` (13 subsequent siblings)
31 siblings, 0 replies; 33+ messages in thread
From: Alex Bennée @ 2026-04-22 10:10 UTC (permalink / raw)
To: qemu-devel
Cc: Alexander Graf, qemu-arm, Peter Maydell, Paolo Bonzini,
Mohamed Mediouni, kvm, Pedro Barbuda, Alex Bennée,
Richard Henderson
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.
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
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 bbf0f6be961..4cfc7f99698 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] 33+ messages in thread
* [PATCH v2 19/31] target/arm: make hvf use syndrome helpers for decode
2026-04-22 10:10 [PATCH v2 00/31] target/arm: fully model WFxT instructions for A-profile Alex Bennée
` (17 preceding siblings ...)
2026-04-22 10:10 ` [PATCH v2 18/31] target/arm: make whpx use syndrome helpers for decode Alex Bennée
@ 2026-04-22 10:10 ` Alex Bennée
2026-04-22 10:10 ` [PATCH v2 20/31] target/arm: use syndrome helpers in merge_syn_data_abort Alex Bennée
` (12 subsequent siblings)
31 siblings, 0 replies; 33+ messages in thread
From: Alex Bennée @ 2026-04-22 10:10 UTC (permalink / raw)
To: qemu-devel
Cc: Alexander Graf, qemu-arm, Peter Maydell, Paolo Bonzini,
Mohamed Mediouni, kvm, Pedro Barbuda, Alex Bennée,
Richard Henderson
Rather than open coding a bunch of shifts and masks we can use the
syndrome definitions.
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
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] 33+ messages in thread
* [PATCH v2 20/31] target/arm: use syndrome helpers in merge_syn_data_abort
2026-04-22 10:10 [PATCH v2 00/31] target/arm: fully model WFxT instructions for A-profile Alex Bennée
` (18 preceding siblings ...)
2026-04-22 10:10 ` [PATCH v2 19/31] target/arm: make hvf " Alex Bennée
@ 2026-04-22 10:10 ` Alex Bennée
2026-04-22 10:10 ` [PATCH v2 21/31] target/arm: use syndrome helpers to query VNCR bit Alex Bennée
` (11 subsequent siblings)
31 siblings, 0 replies; 33+ messages in thread
From: Alex Bennée @ 2026-04-22 10:10 UTC (permalink / raw)
To: qemu-devel
Cc: Alexander Graf, qemu-arm, Peter Maydell, Paolo Bonzini,
Mohamed Mediouni, kvm, Pedro Barbuda, Alex Bennée,
Richard Henderson
One more step to removing the old defines.
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
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] 33+ messages in thread
* [PATCH v2 21/31] target/arm: use syndrome helpers to query VNCR bit
2026-04-22 10:10 [PATCH v2 00/31] target/arm: fully model WFxT instructions for A-profile Alex Bennée
` (19 preceding siblings ...)
2026-04-22 10:10 ` [PATCH v2 20/31] target/arm: use syndrome helpers in merge_syn_data_abort Alex Bennée
@ 2026-04-22 10:10 ` Alex Bennée
2026-04-22 10:10 ` [PATCH v2 22/31] target/arm: remove old syndrome defines Alex Bennée
` (10 subsequent siblings)
31 siblings, 0 replies; 33+ messages in thread
From: Alex Bennée @ 2026-04-22 10:10 UTC (permalink / raw)
To: qemu-devel
Cc: Alexander Graf, qemu-arm, Peter Maydell, Paolo Bonzini,
Mohamed Mediouni, kvm, Pedro Barbuda, Alex Bennée,
Richard Henderson
These are only valid for data abort syndromes.
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
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] 33+ messages in thread
* [PATCH v2 22/31] target/arm: remove old syndrome defines
2026-04-22 10:10 [PATCH v2 00/31] target/arm: fully model WFxT instructions for A-profile Alex Bennée
` (20 preceding siblings ...)
2026-04-22 10:10 ` [PATCH v2 21/31] target/arm: use syndrome helpers to query VNCR bit Alex Bennée
@ 2026-04-22 10:10 ` Alex Bennée
2026-04-22 10:10 ` [PATCH v2 23/31] target/arm: report register in WFIT syndromes Alex Bennée
` (9 subsequent siblings)
31 siblings, 0 replies; 33+ messages in thread
From: Alex Bennée @ 2026-04-22 10:10 UTC (permalink / raw)
To: qemu-devel
Cc: Alexander Graf, qemu-arm, Peter Maydell, Paolo Bonzini,
Mohamed Mediouni, kvm, Pedro Barbuda, Alex Bennée,
Richard Henderson
Now everything is defined with registerfields we can drop the old
defines.
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
---
v2
- remove stuff dropped earlier
---
target/arm/syndrome.h | 9 ---------
1 file changed, 9 deletions(-)
diff --git a/target/arm/syndrome.h b/target/arm/syndrome.h
index d4dfab8cd15..04a71eebcb5 100644
--- a/target/arm/syndrome.h
+++ b/target/arm/syndrome.h
@@ -106,15 +106,6 @@ typedef enum {
GCS_IT_GCSPOPX = 9,
} GCSInstructionType;
-#define ARM_EL_EC_LENGTH 6
-#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] 33+ messages in thread
* [PATCH v2 23/31] target/arm: report register in WFIT syndromes
2026-04-22 10:10 [PATCH v2 00/31] target/arm: fully model WFxT instructions for A-profile Alex Bennée
` (21 preceding siblings ...)
2026-04-22 10:10 ` [PATCH v2 22/31] target/arm: remove old syndrome defines Alex Bennée
@ 2026-04-22 10:10 ` Alex Bennée
2026-04-22 10:10 ` [PATCH v2 24/31] target/arm: teach arm_cpu_has_work about halting reasons Alex Bennée
` (8 subsequent siblings)
31 siblings, 0 replies; 33+ messages in thread
From: Alex Bennée @ 2026-04-22 10:10 UTC (permalink / raw)
To: qemu-devel
Cc: Alexander Graf, qemu-arm, Peter Maydell, Paolo Bonzini,
Mohamed Mediouni, kvm, Pedro Barbuda, Alex Bennée,
Richard Henderson
Pass the register number (rd) to the wfit helper and report it in the
syndrome ISS.
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
---
v2
- drop stale TODO
- fixup stale commit comment (WFIT fix already merged)
- make rv a bool
- make ti a enum type
---
target/arm/syndrome.h | 11 ++++++++++-
target/arm/tcg/helper-defs.h | 2 +-
target/arm/tcg/op_helper.c | 7 ++++---
target/arm/tcg/translate-a64.c | 2 +-
4 files changed, 16 insertions(+), 6 deletions(-)
diff --git a/target/arm/syndrome.h b/target/arm/syndrome.h
index 04a71eebcb5..4d1f1c529e2 100644
--- a/target/arm/syndrome.h
+++ b/target/arm/syndrome.h
@@ -670,7 +670,14 @@ 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)
+typedef enum {
+ WFI = 0b00,
+ WFE = 0b01,
+ WFIT = 0b10,
+ WFET = 0xb11
+} wfx_ti;
+
+static inline uint32_t syn_wfx(int cv, int cond, int rn, bool rv, wfx_ti ti, bool is_16bit)
{
uint32_t res = syn_set_ec(0, EC_WFX_TRAP);
res = FIELD_DP32(res, SYNDROME, IL, !is_16bit);
@@ -678,6 +685,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..652611b4313 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, false, WFI, 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, true, WFIT, 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] 33+ messages in thread
* [PATCH v2 24/31] target/arm: teach arm_cpu_has_work about halting reasons
2026-04-22 10:10 [PATCH v2 00/31] target/arm: fully model WFxT instructions for A-profile Alex Bennée
` (22 preceding siblings ...)
2026-04-22 10:10 ` [PATCH v2 23/31] target/arm: report register in WFIT syndromes Alex Bennée
@ 2026-04-22 10:10 ` Alex Bennée
2026-04-22 10:10 ` [PATCH v2 25/31] target/arm: redefine event stream fields Alex Bennée
` (7 subsequent siblings)
31 siblings, 0 replies; 33+ messages in thread
From: Alex Bennée @ 2026-04-22 10:10 UTC (permalink / raw)
To: qemu-devel
Cc: Alexander Graf, qemu-arm, Peter Maydell, Paolo Bonzini,
Mohamed Mediouni, kvm, Pedro Barbuda, Alex Bennée
With the advent of WFE and WFI we need to pay closer attention to the
reason why the vCPU may be sleeping to figure out if we should wake
it up.
Create env->halt_reason to track this and then re-order the tests so
we:
- ignore everything is the vCPU is powered off
- wake up if the event_register is set and we were in a WFE
- otherwise any IRQ event does wake the vCPU up.
Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
---
target/arm/cpu.h | 27 +++++++++++++++++++++++++
target/arm/arm-powerctl.c | 4 +++-
target/arm/cpu.c | 40 +++++++++++++++++++++++++++-----------
target/arm/kvm.c | 5 +++--
target/arm/machine.c | 2 +-
target/arm/tcg/op_helper.c | 3 +++
6 files changed, 66 insertions(+), 15 deletions(-)
diff --git a/target/arm/cpu.h b/target/arm/cpu.h
index 657ff4ab20b..98cdfa6f130 100644
--- a/target/arm/cpu.h
+++ b/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.
@@ -1691,6 +1707,17 @@ static inline void xpsr_write(CPUARMState *env, uint32_t val, uint32_t mask)
#endif
}
+/**
+ * arm_set_cpu_power_state() - set power state synced with halt_reason
+ */
+static inline void arm_set_cpu_power_state(ARMCPU *cpu, ARMPSCIState state)
+{
+ CPUARMState *env = &cpu->env;
+
+ cpu->power_state = state;
+ env->halt_reason = (state == PSCI_OFF) ? HALT_PSCI : NOT_HALTED;
+}
+
#define HCR_VM (1ULL << 0)
#define HCR_SWIO (1ULL << 1)
#define HCR_PTW (1ULL << 2)
diff --git a/target/arm/arm-powerctl.c b/target/arm/arm-powerctl.c
index a788376d1d3..4ca63a54443 100644
--- a/target/arm/arm-powerctl.c
+++ b/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;
}
@@ -186,6 +187,7 @@ static void arm_set_cpu_on_and_reset_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;
}
@@ -239,7 +241,7 @@ static void arm_set_cpu_off_async_work(CPUState *target_cpu_state,
ARMCPU *target_cpu = ARM_CPU(target_cpu_state);
assert(bql_locked());
- target_cpu->power_state = PSCI_OFF;
+ arm_set_cpu_power_state(target_cpu, PSCI_OFF);
target_cpu_state->halted = 1;
target_cpu_state->exception_index = EXCP_HLT;
}
diff --git a/target/arm/cpu.c b/target/arm/cpu.c
index ccc47c8a9ad..124be8c401e 100644
--- a/target/arm/cpu.c
+++ b/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 arm_set_cpu_on_and_reset_async_work()
+ */
+ 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 */
@@ -250,7 +268,7 @@ static void arm_cpu_reset_hold(Object *obj, ResetType type)
env->vfp.xregs[ARM_VFP_MVFR1] = cpu->isar.mvfr1;
env->vfp.xregs[ARM_VFP_MVFR2] = cpu->isar.mvfr2;
- cpu->power_state = cs->start_powered_off ? PSCI_OFF : PSCI_ON;
+ arm_set_cpu_power_state(cpu, cs->start_powered_off ? PSCI_OFF : PSCI_ON);
if (arm_feature(env, ARM_FEATURE_AARCH64)) {
/* 64 bit CPUs always start in 64 bit mode */
diff --git a/target/arm/kvm.c b/target/arm/kvm.c
index d4a68874b88..c08e4797b32 100644
--- a/target/arm/kvm.c
+++ b/target/arm/kvm.c
@@ -1143,11 +1143,12 @@ static int kvm_arm_sync_mpstate_to_qemu(ARMCPU *cpu)
if (cap_has_mp_state) {
struct kvm_mp_state mp_state;
int ret = kvm_vcpu_ioctl(CPU(cpu), KVM_GET_MP_STATE, &mp_state);
+ ARMPSCIState state;
if (ret) {
return ret;
}
- cpu->power_state = (mp_state.mp_state == KVM_MP_STATE_STOPPED) ?
- PSCI_OFF : PSCI_ON;
+ state = (mp_state.mp_state == KVM_MP_STATE_STOPPED) ? PSCI_OFF : PSCI_ON;
+ arm_set_cpu_power_state(cpu, state);
}
return 0;
}
diff --git a/target/arm/machine.c b/target/arm/machine.c
index b0e499515cf..62401c5a3ea 100644
--- a/target/arm/machine.c
+++ b/target/arm/machine.c
@@ -916,7 +916,7 @@ static int get_power(QEMUFile *f, void *opaque, size_t size,
{
ARMCPU *cpu = opaque;
bool powered_off = qemu_get_byte(f);
- cpu->power_state = powered_off ? PSCI_OFF : PSCI_ON;
+ arm_set_cpu_power_state(cpu, powered_off ? PSCI_OFF : PSCI_ON);
return 0;
}
diff --git a/target/arm/tcg/op_helper.c b/target/arm/tcg/op_helper.c
index 652611b4313..46c745077d5 100644
--- a/target/arm/tcg/op_helper.c
+++ b/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);
--
2.47.3
^ permalink raw reply related [flat|nested] 33+ messages in thread
* [PATCH v2 25/31] target/arm: redefine event stream fields
2026-04-22 10:10 [PATCH v2 00/31] target/arm: fully model WFxT instructions for A-profile Alex Bennée
` (23 preceding siblings ...)
2026-04-22 10:10 ` [PATCH v2 24/31] target/arm: teach arm_cpu_has_work about halting reasons Alex Bennée
@ 2026-04-22 10:10 ` Alex Bennée
2026-04-22 10:10 ` [PATCH v2 26/31] target/arm: ensure aarch64 DISAS_WFE will exit Alex Bennée
` (6 subsequent siblings)
31 siblings, 0 replies; 33+ messages in thread
From: Alex Bennée @ 2026-04-22 10:10 UTC (permalink / raw)
To: qemu-devel
Cc: Alexander Graf, qemu-arm, Peter Maydell, Paolo Bonzini,
Mohamed Mediouni, kvm, Pedro Barbuda, Alex Bennée,
Richard Henderson
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.
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
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 85980f0e69a..dc593f1fec8 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 40dd070d2c1..81a07ca42d0 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] 33+ messages in thread
* [PATCH v2 26/31] target/arm: ensure aarch64 DISAS_WFE will exit
2026-04-22 10:10 [PATCH v2 00/31] target/arm: fully model WFxT instructions for A-profile Alex Bennée
` (24 preceding siblings ...)
2026-04-22 10:10 ` [PATCH v2 25/31] target/arm: redefine event stream fields Alex Bennée
@ 2026-04-22 10:10 ` Alex Bennée
2026-04-22 10:10 ` [PATCH v2 27/31] target/arm: implements SEV/SEVL for all modes Alex Bennée
` (5 subsequent siblings)
31 siblings, 0 replies; 33+ messages in thread
From: Alex Bennée @ 2026-04-22 10:10 UTC (permalink / raw)
To: qemu-devel
Cc: Alexander Graf, qemu-arm, Peter Maydell, Paolo Bonzini,
Mohamed Mediouni, kvm, Pedro Barbuda, Alex Bennée,
Richard Henderson
This mirrors the logic for DISAS_WFE in 32 bit world.
Fixes: 252ec405768 (target-arm: implement WFE/YIELD as a yield for AArch64)
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
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] 33+ messages in thread
* [PATCH v2 27/31] target/arm: implements SEV/SEVL for all modes
2026-04-22 10:10 [PATCH v2 00/31] target/arm: fully model WFxT instructions for A-profile Alex Bennée
` (25 preceding siblings ...)
2026-04-22 10:10 ` [PATCH v2 26/31] target/arm: ensure aarch64 DISAS_WFE will exit Alex Bennée
@ 2026-04-22 10:10 ` Alex Bennée
2026-04-22 10:10 ` [PATCH v2 28/31] target/arm: hoist event broadcast code into a helper Alex Bennée
` (4 subsequent siblings)
31 siblings, 0 replies; 33+ messages in thread
From: Alex Bennée @ 2026-04-22 10:10 UTC (permalink / raw)
To: qemu-devel
Cc: Alexander Graf, qemu-arm, Peter Maydell, Paolo Bonzini,
Mohamed Mediouni, kvm, Pedro Barbuda, Alex Bennée
Remove the restrictions that make this a M-profile only operation and
enable the instructions for all Arm profiles.
Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
---
v2
- fix alignment in a32.decode
- set bool directly, defend with QEMU_BUILD_BUG_ON
- s/instructions/profiles/
- share get_event_reg between translate/translate-a64
---
target/arm/tcg/translate.h | 18 ++++++++++++++++++
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 | 17 +++++++++++++++++
target/arm/tcg/translate.c | 13 ++++++++-----
8 files changed, 50 insertions(+), 20 deletions(-)
diff --git a/target/arm/tcg/translate.h b/target/arm/tcg/translate.h
index 3e3094a463e..9bf2701a56b 100644
--- a/target/arm/tcg/translate.h
+++ b/target/arm/tcg/translate.h
@@ -864,6 +864,24 @@ static inline void gen_restore_rmode(TCGv_i32 old, TCGv_ptr fpst)
gen_helper_set_rmode(old, old, fpst);
}
+/*
+ * 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 inline void gen_event_reg(void)
+{
+#ifndef CONFIG_USER_ONLY
+ TCGv_i32 set_event = tcg_constant_i32(1);
+ QEMU_BUILD_BUG_ON(sizeof_field(CPUARMState, event_register) != 1);
+ tcg_gen_st8_i32(set_event, tcg_env, offsetof(CPUARMState, event_register));
+#endif
+}
+
/*
* Helpers for implementing sets of trans_* functions.
* Defer the implementation of NAME to FUNC, with optional extra arguments.
diff --git a/target/arm/tcg/a32.decode b/target/arm/tcg/a32.decode
index f2ca4809495..547aa2b1490 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 46c745077d5..655e3f96e78 100644
--- a/target/arm/tcg/op_helper.c
+++ b/target/arm/tcg/op_helper.c
@@ -477,9 +477,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 = true;
- }
+ target_cpu->env.event_register = 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..f30df5dbfed 100644
--- a/target/arm/tcg/translate-a64.c
+++ b/target/arm/tcg/translate-a64.c
@@ -2032,6 +2032,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..59925151fc3 100644
--- a/target/arm/tcg/translate.c
+++ b/target/arm/tcg/translate.c
@@ -3244,17 +3244,20 @@ 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)
+{
+ gen_event_reg();
+ return true;
+}
+
static bool trans_WFE(DisasContext *s, arg_WFE *a)
{
/*
--
2.47.3
^ permalink raw reply related [flat|nested] 33+ messages in thread
* [PATCH v2 28/31] target/arm: hoist event broadcast code into a helper
2026-04-22 10:10 [PATCH v2 00/31] target/arm: fully model WFxT instructions for A-profile Alex Bennée
` (26 preceding siblings ...)
2026-04-22 10:10 ` [PATCH v2 27/31] target/arm: implements SEV/SEVL for all modes Alex Bennée
@ 2026-04-22 10:10 ` Alex Bennée
2026-04-22 10:10 ` [PATCH v2 29/31] target/arm: implement global monitor events Alex Bennée
` (3 subsequent siblings)
31 siblings, 0 replies; 33+ messages in thread
From: Alex Bennée @ 2026-04-22 10:10 UTC (permalink / raw)
To: qemu-devel
Cc: Alexander Graf, qemu-arm, Peter Maydell, Paolo Bonzini,
Mohamed Mediouni, kvm, Pedro Barbuda, Alex Bennée
We will shortly call it from more places.
Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
---
target/arm/internals.h | 19 +++++++++++++++++++
target/arm/tcg/op_helper.c | 9 +--------
2 files changed, 20 insertions(+), 8 deletions(-)
diff --git a/target/arm/internals.h b/target/arm/internals.h
index dc593f1fec8..089f679ac0a 100644
--- a/target/arm/internals.h
+++ b/target/arm/internals.h
@@ -682,6 +682,25 @@ bool arm_is_psci_call(ARMCPU *cpu, int excp_type);
/* Actually handle a PSCI call */
void arm_handle_psci_call(ARMCPU *cpu);
+/**
+ * arm_broadcast_event: set the event_register for all PEs
+ *
+ * This kicks all PEs which will up which are waiting on the event
+ * register.
+ */
+static inline void arm_broadcast_event(void)
+{
+ CPUState *cs;
+
+ CPU_FOREACH(cs) {
+ ARMCPU *target_cpu = ARM_CPU(cs);
+ target_cpu->env.event_register = true;
+ if (!qemu_cpu_is_self(cs)) {
+ qemu_cpu_kick(cs);
+ }
+ }
+}
+
/**
* arm_clear_exclusive: clear the exclusive monitor
* @env: CPU env
diff --git a/target/arm/tcg/op_helper.c b/target/arm/tcg/op_helper.c
index 655e3f96e78..6a2be85fcaa 100644
--- a/target/arm/tcg/op_helper.c
+++ b/target/arm/tcg/op_helper.c
@@ -474,14 +474,7 @@ void HELPER(wfit)(CPUARMState *env, uint32_t rd)
void HELPER(sev)(CPUARMState *env)
{
- CPUState *cs = env_cpu(env);
- CPU_FOREACH(cs) {
- ARMCPU *target_cpu = ARM_CPU(cs);
- target_cpu->env.event_register = true;
- if (!qemu_cpu_is_self(cs)) {
- qemu_cpu_kick(cs);
- }
- }
+ arm_broadcast_event();
}
void HELPER(wfe)(CPUARMState *env)
--
2.47.3
^ permalink raw reply related [flat|nested] 33+ messages in thread
* [PATCH v2 29/31] target/arm: implement global monitor events
2026-04-22 10:10 [PATCH v2 00/31] target/arm: fully model WFxT instructions for A-profile Alex Bennée
` (27 preceding siblings ...)
2026-04-22 10:10 ` [PATCH v2 28/31] target/arm: hoist event broadcast code into a helper Alex Bennée
@ 2026-04-22 10:10 ` Alex Bennée
2026-04-22 10:10 ` [PATCH v2 30/31] target/arm: enable event stream on WFE instructions Alex Bennée
` (2 subsequent siblings)
31 siblings, 0 replies; 33+ messages in thread
From: Alex Bennée @ 2026-04-22 10:10 UTC (permalink / raw)
To: qemu-devel
Cc: Alexander Graf, qemu-arm, Peter Maydell, Paolo Bonzini,
Mohamed Mediouni, kvm, Pedro Barbuda, 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).
We special case STLR/STL (Store Release) instructions to generate
events because their use is a suggested pattern for clearing locks
that might be sleeping. We only trigger the event if we detect an
exclusive instruction is running.
Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
---
v2
- add gen_global_event_reg() and use that
- add handling for STL/STLR
---
target/arm/internals.h | 1 +
target/arm/tcg/translate.h | 14 ++++++++++++++
target/arm/tcg/translate-a64.c | 23 +++++++++++++++++++++++
target/arm/tcg/translate.c | 20 ++++++++++++++++++++
4 files changed, 58 insertions(+)
diff --git a/target/arm/internals.h b/target/arm/internals.h
index 089f679ac0a..7045b4a56bd 100644
--- a/target/arm/internals.h
+++ b/target/arm/internals.h
@@ -709,6 +709,7 @@ static inline void arm_broadcast_event(void)
static inline void arm_clear_exclusive(CPUARMState *env)
{
env->exclusive_addr = -1;
+ arm_broadcast_event();
}
/**
diff --git a/target/arm/tcg/translate.h b/target/arm/tcg/translate.h
index 9bf2701a56b..01053060af4 100644
--- a/target/arm/tcg/translate.h
+++ b/target/arm/tcg/translate.h
@@ -882,6 +882,20 @@ static inline void gen_event_reg(void)
#endif
}
+/*
+ * Some events affect all PEs in the same shareability domain. In
+ * practice as we currently model SMP systems as single SoC devices so
+ * we signal them all.
+ */
+static inline void gen_global_event_reg(void)
+{
+#ifndef CONFIG_USER_ONLY
+ /* re-use the SEV helper */
+ gen_helper_sev(tcg_env);
+#endif
+}
+
+
/*
* Helpers for implementing sets of trans_* functions.
* Defer the implementation of NAME to FUNC, with optional extra arguments.
diff --git a/target/arm/tcg/translate-a64.c b/target/arm/tcg/translate-a64.c
index f30df5dbfed..a1b0cc9508e 100644
--- a/target/arm/tcg/translate-a64.c
+++ b/target/arm/tcg/translate-a64.c
@@ -2253,6 +2253,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_global_event_reg();
return true;
}
@@ -3407,6 +3408,14 @@ static void gen_store_exclusive(DisasContext *s, int rd, int rt, int rt2,
tcg_gen_setcond_i64(TCG_COND_NE, tmp, tmp, cpu_exclusive_val);
}
tcg_gen_mov_i64(cpu_reg(s, rd), tmp);
+
+ /*
+ * On a successful StoreExcl the global monitor transitions from
+ * Exclusive to Open Access and at that point generate an Event
+ * for PEs in the same memory sharing domain.
+ */
+ gen_global_event_reg();
+
tcg_gen_br(done_label);
gen_set_label(fail_label);
@@ -3544,6 +3553,7 @@ static bool trans_STLR(DisasContext *s, arg_stlr *a)
TCGv_i64 clean_addr;
MemOp memop;
bool iss_sf = ldst_iss_sf(a->sz, false, false);
+ TCGLabel *skip_monitor_event = gen_new_label();
/*
* StoreLORelease is the same as Store-Release for QEMU, but
@@ -3562,6 +3572,19 @@ static bool trans_STLR(DisasContext *s, arg_stlr *a)
true, a->rn != 31, memop);
do_gpr_st(s, cpu_reg(s, a->rt), clean_addr, memop, true, a->rt,
iss_sf, a->lasr);
+
+ /*
+ * We don't fully model the global monitor as it would be very
+ * expensive for every memory access. However in the Arm ARM "Use
+ * of Wait for Event (WFE) and Send Event (SEV) with lock" it does
+ * give the example of using STLR to clear a lock. So if a lock is
+ * active trigger the global event register so we don't deadlock
+ * while sleeping.
+ */
+ tcg_gen_brcondi_i64(TCG_COND_EQ, cpu_exclusive_addr, -1, skip_monitor_event);
+ gen_global_event_reg();
+ gen_set_label(skip_monitor_event);
+
return true;
}
diff --git a/target/arm/tcg/translate.c b/target/arm/tcg/translate.c
index 59925151fc3..18d64620e40 100644
--- a/target/arm/tcg/translate.c
+++ b/target/arm/tcg/translate.c
@@ -2116,6 +2116,12 @@ static void gen_store_exclusive(DisasContext *s, int rd, int rt, int rt2,
tcg_gen_setcond_i32(TCG_COND_NE, t0, t0, t2);
}
tcg_gen_mov_i32(cpu_R[rd], t0);
+ /*
+ * On a successful StoreExcl the global monitor transitions from
+ * Exclusive to Open Access and at that point generate an Event
+ * for PEs in the same memory sharing domain.
+ */
+ gen_global_event_reg();
tcg_gen_br(done_label);
gen_set_label(fail_label);
@@ -4218,6 +4224,7 @@ static bool trans_STLEXH(DisasContext *s, arg_STREX *a)
static bool op_stl(DisasContext *s, arg_STL *a, MemOp mop)
{
TCGv_i32 addr, tmp;
+ TCGLabel *skip_monitor_event;
if (!ENABLE_ARCH_8) {
return false;
@@ -4230,10 +4237,23 @@ static bool op_stl(DisasContext *s, arg_STL *a, MemOp mop)
addr = load_reg(s, a->rn);
tmp = load_reg(s, a->rt);
+ skip_monitor_event = gen_new_label();
tcg_gen_mb(TCG_MO_ALL | TCG_BAR_STRL);
gen_aa32_st_i32(s, tmp, addr, get_mem_index(s), mop | MO_ALIGN);
disas_set_da_iss(s, mop, a->rt | ISSIsAcqRel | ISSIsWrite);
+ /*
+ * We don't fully model the global monitor as it would be very
+ * expensive for every memory access. However in the Arm ARM "Use
+ * of Wait for Event (WFE) and Send Event (SEV) with lock" it does
+ * give the example of using STL to clear a lock. So if a lock is
+ * active trigger the global event register so we don't deadlock
+ * while sleeping.
+ */
+ tcg_gen_brcondi_i64(TCG_COND_EQ, cpu_exclusive_addr, -1, skip_monitor_event);
+ gen_global_event_reg();
+ gen_set_label(skip_monitor_event);
+
return true;
}
--
2.47.3
^ permalink raw reply related [flat|nested] 33+ messages in thread
* [PATCH v2 30/31] target/arm: enable event stream on WFE instructions
2026-04-22 10:10 [PATCH v2 00/31] target/arm: fully model WFxT instructions for A-profile Alex Bennée
` (28 preceding siblings ...)
2026-04-22 10:10 ` [PATCH v2 29/31] target/arm: implement global monitor events Alex Bennée
@ 2026-04-22 10:10 ` Alex Bennée
2026-04-22 10:10 ` [PATCH v2 31/31] target/arm: implement WFET Alex Bennée
2026-04-22 12:54 ` [PATCH v2 00/31] target/arm: fully model WFxT instructions for A-profile Alex Bennée
31 siblings, 0 replies; 33+ messages in thread
From: Alex Bennée @ 2026-04-22 10:10 UTC (permalink / raw)
To: qemu-devel
Cc: Alexander Graf, qemu-arm, Peter Maydell, Paolo Bonzini,
Mohamed Mediouni, kvm, Pedro Barbuda, 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.
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>
---
v2
- merged target/arm: add gt_calc_next_event_stream
- update to use halt_reason
- made arm_wfxt_timer_cb atomically consume halt_reason
---
target/arm/cpu.c | 13 ++++
target/arm/tcg/op_helper.c | 129 +++++++++++++++++++++++++++++++------
2 files changed, 122 insertions(+), 20 deletions(-)
diff --git a/target/arm/cpu.c b/target/arm/cpu.c
index 124be8c401e..7a6ad45ae08 100644
--- a/target/arm/cpu.c
+++ b/target/arm/cpu.c
@@ -799,10 +799,23 @@ bool arm_cpu_exec_halt(CPUState *cs)
}
#endif
+/*
+ * Unlike almost everything else that messes with the halt_reason and
+ * event_register details the timer callbacks are not in the vCPU
+ * context.
+ *
+ * To prevent races we atomically consume a HALT_WFE and set the event
+ * register. Either way we trigger the an exit event.
+ */
static void arm_wfxt_timer_cb(void *opaque)
{
ARMCPU *cpu = opaque;
CPUState *cs = CPU(cpu);
+ CPUARMState *env = &cpu->env;
+
+ if (qatomic_cmpxchg(&env->halt_reason, HALT_WFE, NOT_HALTED)) {
+ qatomic_set(&env->event_register, true);
+ }
/*
* We expect the CPU to be halted; this will cause arm_cpu_is_work()
diff --git a/target/arm/tcg/op_helper.c b/target/arm/tcg/op_helper.c
index 6a2be85fcaa..030209360e8 100644
--- a/target/arm/tcg/op_helper.c
+++ b/target/arm/tcg/op_helper.c
@@ -477,6 +477,97 @@ void HELPER(sev)(CPUARMState *env)
arm_broadcast_event();
}
+#ifndef CONFIG_USER_ONLY
+/*
+ * 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;
+}
+
+/*
+ * 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.
+ */
+static 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;
+}
+#endif
+
void HELPER(wfe)(CPUARMState *env)
{
#ifdef CONFIG_USER_ONLY
@@ -489,32 +580,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) {
- env->event_register = false;
- return;
- }
+ if (env->event_register) {
+ env->event_register = false;
+ return;
+ }
- env->halt_reason = HALT_WFE;
- 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) {
+ timer_mod(cpu->wfxt_timer, next_event);
+ }
}
+
+ env->halt_reason = HALT_WFE;
+ cs->exception_index = EXCP_HLT;
+ cs->halted = 1;
+ cpu_loop_exit(cs);
#endif
}
--
2.47.3
^ permalink raw reply related [flat|nested] 33+ messages in thread
* [PATCH v2 31/31] target/arm: implement WFET
2026-04-22 10:10 [PATCH v2 00/31] target/arm: fully model WFxT instructions for A-profile Alex Bennée
` (29 preceding siblings ...)
2026-04-22 10:10 ` [PATCH v2 30/31] target/arm: enable event stream on WFE instructions Alex Bennée
@ 2026-04-22 10:10 ` Alex Bennée
2026-04-22 12:54 ` [PATCH v2 00/31] target/arm: fully model WFxT instructions for A-profile Alex Bennée
31 siblings, 0 replies; 33+ messages in thread
From: Alex Bennée @ 2026-04-22 10:10 UTC (permalink / raw)
To: qemu-devel
Cc: Alexander Graf, qemu-arm, Peter Maydell, Paolo Bonzini,
Mohamed Mediouni, kvm, Pedro Barbuda, 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>
---
v2
- fix exception syndrome by using enum value
- use env->halt_reason
---
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 030209360e8..0c7f069a369 100644
--- a/target/arm/tcg/op_helper.c
+++ b/target/arm/tcg/op_helper.c
@@ -607,6 +607,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) {
+ env->event_register = 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, true, WFET, 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) {
+ 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);
+ }
+ }
+
+ env->halt_reason = HALT_WFE;
+ 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 a1b0cc9508e..19e00573979 100644
--- a/target/arm/tcg/translate-a64.c
+++ b/target/arm/tcg/translate-a64.c
@@ -2093,14 +2093,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] 33+ messages in thread
* Re: [PATCH v2 00/31] target/arm: fully model WFxT instructions for A-profile
2026-04-22 10:10 [PATCH v2 00/31] target/arm: fully model WFxT instructions for A-profile Alex Bennée
` (30 preceding siblings ...)
2026-04-22 10:10 ` [PATCH v2 31/31] target/arm: implement WFET Alex Bennée
@ 2026-04-22 12:54 ` Alex Bennée
31 siblings, 0 replies; 33+ messages in thread
From: Alex Bennée @ 2026-04-22 12:54 UTC (permalink / raw)
To: qemu-devel
Cc: Alexander Graf, qemu-arm, Peter Maydell, Paolo Bonzini,
Mohamed Mediouni, kvm, Pedro Barbuda
Alex Bennée <alex.bennee@linaro.org> writes:
> 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.
>
<snip>
> target/arm: enable event stream on WFE instructions
> target/arm: implement WFET
<snip>
I've posted v3 to handle the missing WFE exception and fix a minor
syndrome bug on the WFET exception.
--
Alex Bennée
Virtualisation Tech Lead @ Linaro
^ permalink raw reply [flat|nested] 33+ messages in thread
end of thread, other threads:[~2026-04-22 12:54 UTC | newest]
Thread overview: 33+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-04-22 10:10 [PATCH v2 00/31] target/arm: fully model WFxT instructions for A-profile Alex Bennée
2026-04-22 10:10 ` [PATCH v2 01/31] target/arm: migrate basic syndrome helpers to registerfields Alex Bennée
2026-04-22 10:10 ` [PATCH v2 02/31] target/arm: migrate system/cp trap syndromes " Alex Bennée
2026-04-22 10:10 ` [PATCH v2 03/31] target/arm: migrate FP/SIMD " Alex Bennée
2026-04-22 10:10 ` [PATCH v2 04/31] target/arm: migrate eret " Alex Bennée
2026-04-22 10:10 ` [PATCH v2 05/31] target/arm: migrate SME " Alex Bennée
2026-04-22 10:10 ` [PATCH v2 06/31] target/arm: migrate PAC " Alex Bennée
2026-04-22 10:10 ` [PATCH v2 07/31] target/arm: migrate BTI " Alex Bennée
2026-04-22 10:10 ` [PATCH v2 08/31] target/arm: migrate BXJ " Alex Bennée
2026-04-22 10:10 ` [PATCH v2 09/31] target/arm: migrate Granule Protection traps " Alex Bennée
2026-04-22 10:10 ` [PATCH v2 10/31] target/arm: migrate fault syndromes " Alex Bennée
2026-04-22 10:10 ` [PATCH v2 11/31] target/arm: migrate debug " Alex Bennée
2026-04-22 10:10 ` [PATCH v2 12/31] target/arm: migrate wfx " Alex Bennée
2026-04-22 10:10 ` [PATCH v2 13/31] target/arm: migrate gcs " Alex Bennée
2026-04-22 10:10 ` [PATCH v2 14/31] target/arm: migrate memory op " Alex Bennée
2026-04-22 10:10 ` [PATCH v2 15/31] target/arm: migrate check_hcr_el2_trap to use syndrome helper Alex Bennée
2026-04-22 10:10 ` [PATCH v2 16/31] target/arm: use syndrome helpers in arm_cpu_do_interrupt_aarch32_hyp Alex Bennée
2026-04-22 10:10 ` [PATCH v2 17/31] target/arm: use syndrome helpers to set SAME_EL EC bit Alex Bennée
2026-04-22 10:10 ` [PATCH v2 18/31] target/arm: make whpx use syndrome helpers for decode Alex Bennée
2026-04-22 10:10 ` [PATCH v2 19/31] target/arm: make hvf " Alex Bennée
2026-04-22 10:10 ` [PATCH v2 20/31] target/arm: use syndrome helpers in merge_syn_data_abort Alex Bennée
2026-04-22 10:10 ` [PATCH v2 21/31] target/arm: use syndrome helpers to query VNCR bit Alex Bennée
2026-04-22 10:10 ` [PATCH v2 22/31] target/arm: remove old syndrome defines Alex Bennée
2026-04-22 10:10 ` [PATCH v2 23/31] target/arm: report register in WFIT syndromes Alex Bennée
2026-04-22 10:10 ` [PATCH v2 24/31] target/arm: teach arm_cpu_has_work about halting reasons Alex Bennée
2026-04-22 10:10 ` [PATCH v2 25/31] target/arm: redefine event stream fields Alex Bennée
2026-04-22 10:10 ` [PATCH v2 26/31] target/arm: ensure aarch64 DISAS_WFE will exit Alex Bennée
2026-04-22 10:10 ` [PATCH v2 27/31] target/arm: implements SEV/SEVL for all modes Alex Bennée
2026-04-22 10:10 ` [PATCH v2 28/31] target/arm: hoist event broadcast code into a helper Alex Bennée
2026-04-22 10:10 ` [PATCH v2 29/31] target/arm: implement global monitor events Alex Bennée
2026-04-22 10:10 ` [PATCH v2 30/31] target/arm: enable event stream on WFE instructions Alex Bennée
2026-04-22 10:10 ` [PATCH v2 31/31] target/arm: implement WFET Alex Bennée
2026-04-22 12:54 ` [PATCH v2 00/31] target/arm: fully model WFxT instructions for A-profile Alex Bennée
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox