* [PATCH v7 1/8] target/arm: fix WFET typo in syndrome
2026-05-29 8:29 [PATCH v7 0/8] target/arm: fully model WFxT instructions for A-profile Alex Bennée
@ 2026-05-29 8:29 ` Alex Bennée
2026-05-29 8:29 ` [PATCH v7 2/8] target/arm: teach arm_cpu_has_work about halting reasons Alex Bennée
` (7 subsequent siblings)
8 siblings, 0 replies; 17+ messages in thread
From: Alex Bennée @ 2026-05-29 8:29 UTC (permalink / raw)
To: qemu-devel
Cc: Paolo Bonzini, Alexander Graf, Mohamed Mediouni, Peter Maydell,
Pedro Barbuda, qemu-arm, kvm, Alex Bennée, Richard Henderson
A stray x slipped in and we didn't notice! Fortunately we haven't
implemented WFET yet so nothing is affected. But we are about to so
lets fix it.
Fixes: 4575da5ecb7 (target/arm: report register in WFIT syndromes)
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
---
v7
- mention how we got away with it
---
target/arm/syndrome.h | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/target/arm/syndrome.h b/target/arm/syndrome.h
index 4d1f1c529e2..0eb54c15ce7 100644
--- a/target/arm/syndrome.h
+++ b/target/arm/syndrome.h
@@ -674,7 +674,7 @@ typedef enum {
WFI = 0b00,
WFE = 0b01,
WFIT = 0b10,
- WFET = 0xb11
+ WFET = 0b11
} wfx_ti;
static inline uint32_t syn_wfx(int cv, int cond, int rn, bool rv, wfx_ti ti, bool is_16bit)
--
2.47.3
^ permalink raw reply related [flat|nested] 17+ messages in thread* [PATCH v7 2/8] target/arm: teach arm_cpu_has_work about halting reasons
2026-05-29 8:29 [PATCH v7 0/8] target/arm: fully model WFxT instructions for A-profile Alex Bennée
2026-05-29 8:29 ` [PATCH v7 1/8] target/arm: fix WFET typo in syndrome Alex Bennée
@ 2026-05-29 8:29 ` Alex Bennée
2026-05-29 8:29 ` [PATCH v7 3/8] target/arm: redefine event stream fields Alex Bennée
` (6 subsequent siblings)
8 siblings, 0 replies; 17+ messages in thread
From: Alex Bennée @ 2026-05-29 8:29 UTC (permalink / raw)
To: qemu-devel
Cc: Paolo Bonzini, Alexander Graf, Mohamed Mediouni, Peter Maydell,
Pedro Barbuda, qemu-arm, kvm, Alex Bennée, Richard Henderson
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.
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
---
v3
- move arm_set_cpu_power_state to internals.h
- drop excess brackets
v5
- more arm_set_cpu_power_state cases
---
target/arm/cpu.h | 16 +++++++++++++++
target/arm/internals.h | 11 +++++++++++
target/arm/arm-powerctl.c | 6 +++---
target/arm/cpu.c | 40 +++++++++++++++++++++++++++-----------
target/arm/kvm.c | 5 +++--
target/arm/machine.c | 2 +-
target/arm/tcg/op_helper.c | 3 +++
7 files changed, 66 insertions(+), 17 deletions(-)
diff --git a/target/arm/cpu.h b/target/arm/cpu.h
index 85552b573c4..dfc369b5844 100644
--- a/target/arm/cpu.h
+++ b/target/arm/cpu.h
@@ -224,6 +224,19 @@ typedef enum ARMFPStatusFlavour {
/* Architecturally there are 128 PPIs in a GICv5 */
#define GICV5_NUM_PPIS 128
+/**
+ * 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];
@@ -746,6 +759,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.
diff --git a/target/arm/internals.h b/target/arm/internals.h
index ae5afc5362e..fb9df50da29 100644
--- a/target/arm/internals.h
+++ b/target/arm/internals.h
@@ -2027,4 +2027,15 @@ bool arm_cpu_match_cpreg_mig_tolerance(ARMCPU *cpu, uint64_t kvmidx,
ARMCPRegMigToleranceType type);
+/**
+ * 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;
+}
+
#endif
diff --git a/target/arm/arm-powerctl.c b/target/arm/arm-powerctl.c
index a788376d1d3..a06be5cc997 100644
--- a/target/arm/arm-powerctl.c
+++ b/target/arm/arm-powerctl.c
@@ -78,7 +78,7 @@ static void arm_set_cpu_on_async_work(CPUState *target_cpu_state,
/* Finally set the power status */
assert(bql_locked());
- target_cpu->power_state = PSCI_ON;
+ arm_set_cpu_power_state(target_cpu, PSCI_ON);
}
int arm_set_cpu_on(uint64_t cpuid, uint64_t entry, uint64_t context_id,
@@ -186,7 +186,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->power_state = PSCI_ON;
+ arm_set_cpu_power_state(target_cpu, PSCI_ON);
}
int arm_set_cpu_on_and_reset(uint64_t cpuid)
@@ -239,7 +239,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 a13e6dae2a2..8771b695d9d 100644
--- a/target/arm/cpu.c
+++ b/target/arm/cpu.c
@@ -145,18 +145,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 */
@@ -327,7 +345,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 7d194ea112b..a54ef51ec2a 100644
--- a/target/arm/kvm.c
+++ b/target/arm/kvm.c
@@ -1149,11 +1149,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 58f8dfd53c8..fde3b3e8d75 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 e8f0996ed39..504526153a6 100644
--- a/target/arm/tcg/op_helper.c
+++ b/target/arm/tcg/op_helper.c
@@ -402,6 +402,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);
@@ -463,6 +464,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);
@@ -507,6 +509,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] 17+ messages in thread* [PATCH v7 3/8] target/arm: redefine event stream fields
2026-05-29 8:29 [PATCH v7 0/8] target/arm: fully model WFxT instructions for A-profile Alex Bennée
2026-05-29 8:29 ` [PATCH v7 1/8] target/arm: fix WFET typo in syndrome Alex Bennée
2026-05-29 8:29 ` [PATCH v7 2/8] target/arm: teach arm_cpu_has_work about halting reasons Alex Bennée
@ 2026-05-29 8:29 ` Alex Bennée
2026-05-29 8:29 ` [PATCH v7 4/8] target/arm: ensure aarch64 DISAS_WFE will exit Alex Bennée
` (5 subsequent siblings)
8 siblings, 0 replies; 17+ messages in thread
From: Alex Bennée @ 2026-05-29 8:29 UTC (permalink / raw)
To: qemu-devel
Cc: Paolo Bonzini, Alexander Graf, Mohamed Mediouni, Peter Maydell,
Pedro Barbuda, qemu-arm, kvm, 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 fb9df50da29..93f5bd0e830 100644
--- a/target/arm/internals.h
+++ b/target/arm/internals.h
@@ -272,14 +272,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)
@@ -289,7 +292,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 34487eeaa36..bed58e65b4d 100644
--- a/target/arm/helper.c
+++ b/target/arm/helper.c
@@ -1769,9 +1769,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 |
@@ -1786,7 +1786,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] 17+ messages in thread* [PATCH v7 4/8] target/arm: ensure aarch64 DISAS_WFE will exit
2026-05-29 8:29 [PATCH v7 0/8] target/arm: fully model WFxT instructions for A-profile Alex Bennée
` (2 preceding siblings ...)
2026-05-29 8:29 ` [PATCH v7 3/8] target/arm: redefine event stream fields Alex Bennée
@ 2026-05-29 8:29 ` Alex Bennée
2026-05-29 8:29 ` [PATCH v7 5/8] target/arm: implements SEV/SEVL for all modes Alex Bennée
` (4 subsequent siblings)
8 siblings, 0 replies; 17+ messages in thread
From: Alex Bennée @ 2026-05-29 8:29 UTC (permalink / raw)
To: qemu-devel
Cc: Paolo Bonzini, Alexander Graf, Mohamed Mediouni, Peter Maydell,
Pedro Barbuda, qemu-arm, kvm, Alex Bennée, Richard Henderson
This mirrors the logic for DISAS_WFE in 32 bit world. As the WFE/WFI
have similar behaviours shuffle the case statements around a little
and update the commentary to cover both.
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>
---
v4
- shuffle case statements, unify the comments.
---
target/arm/tcg/translate-a64.c | 24 ++++++++++++------------
1 file changed, 12 insertions(+), 12 deletions(-)
diff --git a/target/arm/tcg/translate-a64.c b/target/arm/tcg/translate-a64.c
index 15b40090c0f..c20269b1501 100644
--- a/target/arm/tcg/translate-a64.c
+++ b/target/arm/tcg/translate-a64.c
@@ -10939,25 +10939,25 @@ static void aarch64_tr_tb_stop(DisasContextBase *dcbase, CPUState *cpu)
case DISAS_NORETURN:
case DISAS_SWI:
break;
- case DISAS_WFE:
- gen_a64_update_pc(dc, 4);
- gen_helper_wfe(tcg_env);
- break;
case DISAS_YIELD:
gen_a64_update_pc(dc, 4);
gen_helper_yield(tcg_env);
break;
+ /*
+ * Both WFE/WFI can cause exceptions or exit the loop to
+ * halt so we have to make sure we have rectified the PC.
+ * However they can also return directly if they don't
+ * enter a wait state so we must add an exit block so we exit
+ * the loop and check for interrupts.
+ */
+ case DISAS_WFE:
+ gen_a64_update_pc(dc, 4);
+ gen_helper_wfe(tcg_env);
+ tcg_gen_exit_tb(NULL, 0);
+ break;
case DISAS_WFI:
- /*
- * This is a special case because we don't want to just halt
- * the CPU if trying to debug across a WFI.
- */
gen_a64_update_pc(dc, 4);
gen_helper_wfi(tcg_env, tcg_constant_i32(4));
- /*
- * The helper doesn't necessarily throw an exception, but we
- * must go back to the main loop to check for interrupts anyway.
- */
tcg_gen_exit_tb(NULL, 0);
break;
}
--
2.47.3
^ permalink raw reply related [flat|nested] 17+ messages in thread* [PATCH v7 5/8] target/arm: implements SEV/SEVL for all modes
2026-05-29 8:29 [PATCH v7 0/8] target/arm: fully model WFxT instructions for A-profile Alex Bennée
` (3 preceding siblings ...)
2026-05-29 8:29 ` [PATCH v7 4/8] target/arm: ensure aarch64 DISAS_WFE will exit Alex Bennée
@ 2026-05-29 8:29 ` Alex Bennée
2026-06-08 15:52 ` Peter Maydell
2026-05-29 8:29 ` [PATCH v7 6/8] target/arm: enable event stream on WFE instructions Alex Bennée
` (3 subsequent siblings)
8 siblings, 1 reply; 17+ messages in thread
From: Alex Bennée @ 2026-05-29 8:29 UTC (permalink / raw)
To: qemu-devel
Cc: Paolo Bonzini, Alexander Graf, Mohamed Mediouni, Peter Maydell,
Pedro Barbuda, qemu-arm, kvm, Alex Bennée, Richard Henderson
Remove the restrictions that make this a M-profile only operation and
enable the instructions for all Arm profiles.
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
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 d4bcc5bad4c..b71b1d5be66 100644
--- a/target/arm/tcg/translate.h
+++ b/target/arm/tcg/translate.h
@@ -856,6 +856,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 02c7264cb99..7ea52ac23b9 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 504526153a6..2b1fb1e059d 100644
--- a/target/arm/tcg/op_helper.c
+++ b/target/arm/tcg/op_helper.c
@@ -476,9 +476,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 c20269b1501..4b978c8b958 100644
--- a/target/arm/tcg/translate-a64.c
+++ b/target/arm/tcg/translate-a64.c
@@ -2033,6 +2033,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 c744b163453..e1e5539f571 100644
--- a/target/arm/tcg/translate.c
+++ b/target/arm/tcg/translate.c
@@ -3246,17 +3246,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] 17+ messages in thread* Re: [PATCH v7 5/8] target/arm: implements SEV/SEVL for all modes
2026-05-29 8:29 ` [PATCH v7 5/8] target/arm: implements SEV/SEVL for all modes Alex Bennée
@ 2026-06-08 15:52 ` Peter Maydell
0 siblings, 0 replies; 17+ messages in thread
From: Peter Maydell @ 2026-06-08 15:52 UTC (permalink / raw)
To: Alex Bennée
Cc: qemu-devel, Paolo Bonzini, Alexander Graf, Mohamed Mediouni,
Pedro Barbuda, qemu-arm, kvm, Richard Henderson
On Fri, 29 May 2026 at 09:29, Alex Bennée <alex.bennee@linaro.org> wrote:
>
> Remove the restrictions that make this a M-profile only operation and
> enable the instructions for all Arm profiles.
>
> Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
> 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
> 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/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/translate.c b/target/arm/tcg/translate.c
> index c744b163453..e1e5539f571 100644
> --- a/target/arm/tcg/translate.c
> +++ b/target/arm/tcg/translate.c
> @@ -3246,17 +3246,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
The AArch32 SEV encodings are only SEV for M-profile and for
Armv7A and above -- for v6T2 and earlier they are NOP hints.
We need a feature-check here.
> return true;
> }
>
> +static bool trans_SEVL(DisasContext *s, arg_SEV *a)
> +{
> + gen_event_reg();
> + return true;
The SEVL encodings only exist for v8A -- they are unallocated
must-NOP hints for M-profile and v7A and earlier. We need a
feature-check here.
> +}
> +
> static bool trans_WFE(DisasContext *s, arg_WFE *a)
thanks
-- PMM
^ permalink raw reply [flat|nested] 17+ messages in thread
* [PATCH v7 6/8] target/arm: enable event stream on WFE instructions
2026-05-29 8:29 [PATCH v7 0/8] target/arm: fully model WFxT instructions for A-profile Alex Bennée
` (4 preceding siblings ...)
2026-05-29 8:29 ` [PATCH v7 5/8] target/arm: implements SEV/SEVL for all modes Alex Bennée
@ 2026-05-29 8:29 ` Alex Bennée
2026-05-29 8:29 ` [PATCH v7 7/8] target/arm: handle the WFE trap case Alex Bennée
` (2 subsequent siblings)
8 siblings, 0 replies; 17+ messages in thread
From: Alex Bennée @ 2026-05-29 8:29 UTC (permalink / raw)
To: qemu-devel
Cc: Paolo Bonzini, Alexander Graf, Mohamed Mediouni, Peter Maydell,
Pedro Barbuda, qemu-arm, kvm, Alex Bennée, Richard Henderson
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.
To avoid issues with QEMU's incomplete ldst exclusive handling causing
potential deadlocks in common WFE enabled locking patterns we take
advantage of the architectures flexibility and treat being in the
exclusive region as a reason to exit.
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
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
v4
- skip sleep if in the exclusive region
- update commit message
- remove the CF_PARALLEL guards so we work in smp
v5
- use env_archcpu for ARMCPU rather then expensive QOM cast
- rely on cpu->wfxt_timer to guard event stream leg
v6
- use atomic_xchg to consume event_register
- remove extraneous target_el calculation
---
target/arm/cpu.c | 13 +++
target/arm/tcg/op_helper.c | 142 ++++++++++++++++++++++++++++-----
target/arm/tcg/translate-a64.c | 10 +--
target/arm/tcg/translate.c | 16 +---
4 files changed, 139 insertions(+), 42 deletions(-)
diff --git a/target/arm/cpu.c b/target/arm/cpu.c
index 8771b695d9d..d01b4cee5f0 100644
--- a/target/arm/cpu.c
+++ b/target/arm/cpu.c
@@ -879,10 +879,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 2b1fb1e059d..b803c9bf162 100644
--- a/target/arm/tcg/op_helper.c
+++ b/target/arm/tcg/op_helper.c
@@ -483,6 +483,97 @@ void HELPER(sev)(CPUARMState *env)
}
}
+#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
@@ -495,32 +586,43 @@ 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 = env_archcpu(env);
- if (env->event_register) {
- env->event_register = false;
- return;
- }
+ if (qatomic_xchg(&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);
+ /*
+ * If the CPU has entered the exclusive region we could sleep
+ * until the global monitor moves from Exclusive to Open Access.
+ * However it would be expensive for QEMU to fully model the
+ * global monitor and not doing so would potentially trigger
+ * deadlocks in WFE enabled locking code. However as WFE is a hint
+ * instruction the architecture allows for the PE to leave
+ * low-power state for any reason. QEMU chooses to treat being in
+ * an exclusive region as such and return directly.
+ */
+ if (env->exclusive_addr != -1) {
+ return;
+ }
+
+ /* For A-profile we also can be woken by the event stream */
+ if (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
}
diff --git a/target/arm/tcg/translate-a64.c b/target/arm/tcg/translate-a64.c
index 4b978c8b958..ec03eaa3bbd 100644
--- a/target/arm/tcg/translate-a64.c
+++ b/target/arm/tcg/translate-a64.c
@@ -2052,15 +2052,7 @@ static bool trans_SEVL(DisasContext *s, arg_SEV *a)
static bool trans_WFE(DisasContext *s, arg_WFI *a)
{
- /*
- * When running in MTTCG we don't generate jumps to the yield and
- * WFE helpers as it won't affect the scheduling of other vCPUs.
- * If we wanted to more completely model WFE/SEV so we don't busy
- * spin unnecessarily we would need to do something more involved.
- */
- if (!(tb_cflags(s->base.tb) & CF_PARALLEL)) {
- s->base.is_jmp = DISAS_WFE;
- }
+ s->base.is_jmp = DISAS_WFE;
return true;
}
diff --git a/target/arm/tcg/translate.c b/target/arm/tcg/translate.c
index e1e5539f571..c10cc382d15 100644
--- a/target/arm/tcg/translate.c
+++ b/target/arm/tcg/translate.c
@@ -3262,19 +3262,9 @@ static bool trans_SEVL(DisasContext *s, arg_SEV *a)
static bool trans_WFE(DisasContext *s, arg_WFE *a)
{
- /*
- * When running single-threaded TCG code, use the helper to ensure that
- * the next round-robin scheduled vCPU gets a crack.
- *
- * For Cortex-M, we implement the architectural WFE behavior (sleeping
- * until an event occurs or the Event Register is set).
- * For other profiles, we currently treat this as a NOP or yield,
- * to preserve existing performance characteristics.
- */
- if (!(tb_cflags(s->base.tb) & CF_PARALLEL)) {
- gen_update_pc(s, curr_insn_len(s));
- s->base.is_jmp = DISAS_WFE;
- }
+ /* For WFE, halt the vCPU until an event. */
+ gen_update_pc(s, curr_insn_len(s));
+ s->base.is_jmp = DISAS_WFE;
return true;
}
--
2.47.3
^ permalink raw reply related [flat|nested] 17+ messages in thread* [PATCH v7 7/8] target/arm: handle the WFE trap case
2026-05-29 8:29 [PATCH v7 0/8] target/arm: fully model WFxT instructions for A-profile Alex Bennée
` (5 preceding siblings ...)
2026-05-29 8:29 ` [PATCH v7 6/8] target/arm: enable event stream on WFE instructions Alex Bennée
@ 2026-05-29 8:29 ` Alex Bennée
2026-06-08 15:53 ` Peter Maydell
2026-05-29 8:29 ` [PATCH v7 8/8] target/arm: implement WFET Alex Bennée
2026-06-08 13:51 ` [PATCH v7 0/8] target/arm: fully model WFxT instructions for A-profile Peter Maydell
8 siblings, 1 reply; 17+ messages in thread
From: Alex Bennée @ 2026-05-29 8:29 UTC (permalink / raw)
To: qemu-devel
Cc: Paolo Bonzini, Alexander Graf, Mohamed Mediouni, Peter Maydell,
Pedro Barbuda, qemu-arm, kvm, Alex Bennée, Richard Henderson
Now WFE can actually suspend on A-profile we also need to handle when
its trapped. To do this we need to pass the instruction size so we can
deal with the is_16bit syndrome encoding.
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
---
v6
- defer calculating target_el until after the early return
---
target/arm/tcg/helper-defs.h | 2 +-
target/arm/tcg/op_helper.c | 16 +++++++++++++++-
target/arm/tcg/translate-a64.c | 2 +-
target/arm/tcg/translate.c | 2 +-
4 files changed, 18 insertions(+), 4 deletions(-)
diff --git a/target/arm/tcg/helper-defs.h b/target/arm/tcg/helper-defs.h
index a05f2258f29..ebdf09be38a 100644
--- a/target/arm/tcg/helper-defs.h
+++ b/target/arm/tcg/helper-defs.h
@@ -54,7 +54,7 @@ DEF_HELPER_2(exception_swstep, noreturn, env, i32)
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(wfe, void, env, i32)
DEF_HELPER_2(wfit, void, env, i32)
DEF_HELPER_1(yield, void, env)
DEF_HELPER_1(pre_hvc, void, env)
diff --git a/target/arm/tcg/op_helper.c b/target/arm/tcg/op_helper.c
index b803c9bf162..060b155d559 100644
--- a/target/arm/tcg/op_helper.c
+++ b/target/arm/tcg/op_helper.c
@@ -574,7 +574,7 @@ static int64_t gt_calc_next_event_stream(CPUARMState *env)
}
#endif
-void HELPER(wfe)(CPUARMState *env)
+void HELPER(wfe)(CPUARMState *env, uint32_t insn_len)
{
#ifdef CONFIG_USER_ONLY
/*
@@ -592,11 +592,25 @@ void HELPER(wfe)(CPUARMState *env)
*/
CPUState *cs = env_cpu(env);
ARMCPU *cpu = env_archcpu(env);
+ uint32_t excp;
+ int target_el;
if (qatomic_xchg(&env->event_register, false)) {
return;
}
+ /* We might sleep, so now we check to see if we should trap */
+ target_el = check_wfx_trap(env, true, &excp);
+ if (target_el) {
+ if (env->aarch64) {
+ env->pc -= insn_len;
+ } else {
+ env->regs[15] -= insn_len;
+ }
+ raise_exception(env, excp, syn_wfx(1, 0xe, 0, false, WFE, insn_len == 2),
+ target_el);
+ }
+
/*
* If the CPU has entered the exclusive region we could sleep
* until the global monitor moves from Exclusive to Open Access.
diff --git a/target/arm/tcg/translate-a64.c b/target/arm/tcg/translate-a64.c
index ec03eaa3bbd..a4603e1a5c7 100644
--- a/target/arm/tcg/translate-a64.c
+++ b/target/arm/tcg/translate-a64.c
@@ -10961,7 +10961,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);
+ gen_helper_wfe(tcg_env, tcg_constant_i32(4));
tcg_gen_exit_tb(NULL, 0);
break;
case DISAS_WFI:
diff --git a/target/arm/tcg/translate.c b/target/arm/tcg/translate.c
index c10cc382d15..1f554f6c271 100644
--- a/target/arm/tcg/translate.c
+++ b/target/arm/tcg/translate.c
@@ -6836,7 +6836,7 @@ static void arm_tr_tb_stop(DisasContextBase *dcbase, CPUState *cpu)
tcg_gen_exit_tb(NULL, 0);
break;
case DISAS_WFE:
- gen_helper_wfe(tcg_env);
+ gen_helper_wfe(tcg_env, tcg_constant_i32(curr_insn_len(dc)));
/*
* The helper can return if the event register is set, so we
* must go back to the main loop to check for events.
--
2.47.3
^ permalink raw reply related [flat|nested] 17+ messages in thread* Re: [PATCH v7 7/8] target/arm: handle the WFE trap case
2026-05-29 8:29 ` [PATCH v7 7/8] target/arm: handle the WFE trap case Alex Bennée
@ 2026-06-08 15:53 ` Peter Maydell
0 siblings, 0 replies; 17+ messages in thread
From: Peter Maydell @ 2026-06-08 15:53 UTC (permalink / raw)
To: Alex Bennée
Cc: qemu-devel, Paolo Bonzini, Alexander Graf, Mohamed Mediouni,
Pedro Barbuda, qemu-arm, kvm, Richard Henderson
On Fri, 29 May 2026 at 09:29, Alex Bennée <alex.bennee@linaro.org> wrote:
>
> Now WFE can actually suspend on A-profile we also need to handle when
> its trapped. To do this we need to pass the instruction size so we can
> deal with the is_16bit syndrome encoding.
>
> Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
> Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
Doesn't this need to go earlier in the patchset? Otherwise there's
a point where WFE can go to sleep but doesn't honour the trap bit.
thanks
-- PMM
^ permalink raw reply [flat|nested] 17+ messages in thread
* [PATCH v7 8/8] target/arm: implement WFET
2026-05-29 8:29 [PATCH v7 0/8] target/arm: fully model WFxT instructions for A-profile Alex Bennée
` (6 preceding siblings ...)
2026-05-29 8:29 ` [PATCH v7 7/8] target/arm: handle the WFE trap case Alex Bennée
@ 2026-05-29 8:29 ` Alex Bennée
2026-06-08 13:51 ` [PATCH v7 0/8] target/arm: fully model WFxT instructions for A-profile Peter Maydell
8 siblings, 0 replies; 17+ messages in thread
From: Alex Bennée @ 2026-05-29 8:29 UTC (permalink / raw)
To: qemu-devel
Cc: Paolo Bonzini, Alexander Graf, Mohamed Mediouni, Peter Maydell,
Pedro Barbuda, qemu-arm, kvm, Alex Bennée, Richard Henderson
Now we have the event stream and SEV/SEVL implemented we can finally
enable WFET for Aarch64.
To avoid issues with QEMU's incomplete ldst exclusive handling causing
potential deadlocks in common WFE enabled locking patterns we take
advantage of the architectures flexibility and treat being in the
exclusive region as a reason to exit.
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
---
v2
- fix exception syndrome by using enum value
- use env->halt_reason
v3
- fix check_wfx_trap(s/false/true/) as it is a WFE
v4
- defer expensive calculations until needed
- treat cs->exclusive_addr as a IMPDEF WFE exit
- update commit message
v5
- use atomic_xchg to consume event_register
---
target/arm/tcg/helper-defs.h | 1 +
target/arm/tcg/op_helper.c | 94 ++++++++++++++++++++++++++++++++++
target/arm/tcg/translate-a64.c | 15 +++---
3 files changed, 103 insertions(+), 7 deletions(-)
diff --git a/target/arm/tcg/helper-defs.h b/target/arm/tcg/helper-defs.h
index ebdf09be38a..5e4d828dd55 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_2(wfe, void, env, i32)
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 060b155d559..b64b80fa653 100644
--- a/target/arm/tcg/op_helper.c
+++ b/target/arm/tcg/op_helper.c
@@ -640,6 +640,100 @@ void HELPER(wfe)(CPUARMState *env, uint32_t insn_len)
#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
+ CPUState *cs = env_cpu(env);
+ uint32_t excp;
+ int target_el;
+ ARMCPU *cpu;
+ uint64_t cntval, timeout, offset, cntvct, nexttick;
+ int64_t next_event;
+
+ /*
+ * As for WFE if the event register is already set we can consume
+ * the event and return immediately.
+ */
+ if (qatomic_xchg(&env->event_register, false)) {
+ return;
+ }
+
+ /*
+ * Don't bother to go into our "low power state" if
+ * we would just wake up immediately.
+ *
+ * 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().
+ */
+ cntval = gt_get_countervalue(env);
+ offset = gt_direct_access_timer_offset(env, GTIMER_VIRT);
+ cntvct = cntval - offset;
+ timeout = env->xregs[rd];
+ if (cpu_has_work(cs) || cntvct >= timeout) {
+ return;
+ }
+
+ /* We might sleep, so now we check to see if we should trap */
+ target_el = check_wfx_trap(env, true, &excp);
+ if (target_el) {
+ env->pc -= 4;
+ raise_exception(env, excp, syn_wfx(1, 0xe, rd, true, WFET, false), target_el);
+ }
+
+ /*
+ * If the CPU has entered the exclusive region we could sleep
+ * until the global monitor moves from Exclusive to Open Access.
+ * However it would be expensive for QEMU to fully model the
+ * global monitor and not doing so would potentially trigger
+ * deadlocks in WFE enabled locking code. However as WFE is a hint
+ * instruction the architecture allows for the PE to leave
+ * low-power state for any reason. QEMU chooses to treat being in
+ * an exclusive region as such and return directly.
+ */
+ if (env->exclusive_addr != -1) {
+ return;
+ }
+
+ /*
+ * Finally work out if the timeout or event stream will kick in
+ * earlier.
+ *
+ * The WFET should time out when CNTVCT_EL0 >= the specified value.
+ */
+ cpu = env_archcpu(env);
+ 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 a4603e1a5c7..fb9a212df4b 100644
--- a/target/arm/tcg/translate-a64.c
+++ b/target/arm/tcg/translate-a64.c
@@ -2086,14 +2086,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] 17+ messages in thread* Re: [PATCH v7 0/8] target/arm: fully model WFxT instructions for A-profile
2026-05-29 8:29 [PATCH v7 0/8] target/arm: fully model WFxT instructions for A-profile Alex Bennée
` (7 preceding siblings ...)
2026-05-29 8:29 ` [PATCH v7 8/8] target/arm: implement WFET Alex Bennée
@ 2026-06-08 13:51 ` Peter Maydell
2026-06-08 15:54 ` Peter Maydell
2026-06-12 17:18 ` Alex Bennée
8 siblings, 2 replies; 17+ messages in thread
From: Peter Maydell @ 2026-06-08 13:51 UTC (permalink / raw)
To: Alex Bennée
Cc: qemu-devel, Paolo Bonzini, Alexander Graf, Mohamed Mediouni,
Pedro Barbuda, qemu-arm, kvm
On Fri, 29 May 2026 at 09:29, Alex Bennée <alex.bennee@linaro.org> wrote:
>
> 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 refactoring from the previous iterations of the patch have now
> been merged.
>
> I've dropped trying to fully model the global monitor in favour of
> taking advantage of the architectural flexibility to have an IMPDEF
> event wake up for any reason. We treat the setting of exclusive_addr
> as such a reason because it indicates the current vCPU is in a ldstx
> exclusive region and we don't want the guest to deadlock. This does mean
> the system won't sleep on WFE enabled locks but people shouldn't be
> relying on QEMU to model real world sleep patterns anyway given the
> efficiency of emulation compared to real HW.
>
> I've written a test case using kvm-unit-tests:
>
> Message-ID: <20260527111822.1563679-1-alex.bennee@linaro.org>
> Date: Wed, 27 May 2026 12:18:21 +0100
> Subject: [kvm-unit-tests PATCH v2] arm: add wfx test case
> From: =?UTF-8?q?Alex=20Benn=C3=A9e?= <alex.bennee@linaro.org>
>
> All patches are now reviewed.
Applied to target-arm.next, thanks.
-- PMM
^ permalink raw reply [flat|nested] 17+ messages in thread* Re: [PATCH v7 0/8] target/arm: fully model WFxT instructions for A-profile
2026-06-08 13:51 ` [PATCH v7 0/8] target/arm: fully model WFxT instructions for A-profile Peter Maydell
@ 2026-06-08 15:54 ` Peter Maydell
2026-06-08 17:01 ` Alex Bennée
2026-06-12 17:18 ` Alex Bennée
1 sibling, 1 reply; 17+ messages in thread
From: Peter Maydell @ 2026-06-08 15:54 UTC (permalink / raw)
To: Alex Bennée
Cc: qemu-devel, Paolo Bonzini, Alexander Graf, Mohamed Mediouni,
Pedro Barbuda, qemu-arm, kvm
On Mon, 8 Jun 2026 at 14:51, Peter Maydell <peter.maydell@linaro.org> wrote:
>
> On Fri, 29 May 2026 at 09:29, Alex Bennée <alex.bennee@linaro.org> wrote:
> >
> > 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 refactoring from the previous iterations of the patch have now
> > been merged.
> >
> > I've dropped trying to fully model the global monitor in favour of
> > taking advantage of the architectural flexibility to have an IMPDEF
> > event wake up for any reason. We treat the setting of exclusive_addr
> > as such a reason because it indicates the current vCPU is in a ldstx
> > exclusive region and we don't want the guest to deadlock. This does mean
> > the system won't sleep on WFE enabled locks but people shouldn't be
> > relying on QEMU to model real world sleep patterns anyway given the
> > efficiency of emulation compared to real HW.
> >
> > I've written a test case using kvm-unit-tests:
> >
> > Message-ID: <20260527111822.1563679-1-alex.bennee@linaro.org>
> > Date: Wed, 27 May 2026 12:18:21 +0100
> > Subject: [kvm-unit-tests PATCH v2] arm: add wfx test case
> > From: =?UTF-8?q?Alex=20Benn=C3=A9e?= <alex.bennee@linaro.org>
> >
> > All patches are now reviewed.
>
>
>
> Applied to target-arm.next, thanks.
This turns out to cause failures in "make check-functional": some
tests now time out. It looks like the patch that triggers this
is the "enable event stream on WFE instructions".
13/79 func-thorough+func-arm-thorough+thorough -
qemu:func-arm-aspeed_rainier ERROR 36.17s
exit status 1
74/79 func-thorough+func-arm-thorough+thorough -
qemu:func-arm-smdkc210 TIMEOUT 90.01s
killed by signal 15 SIGTERM
75/79 func-thorough+func-arm-thorough+thorough - qemu:func-arm-raspi2
TIMEOUT 120.01s killed by signal 15
SIGTERM
76/79 func-thorough+func-arm-thorough+thorough -
qemu:func-arm-quanta_gsj TIMEOUT 240.01s
killed by signal 15 SIGTERM
77/79 func-thorough+func-arm-thorough+thorough - qemu:func-arm-bpim2u
TIMEOUT 500.01s killed by signal 15
SIGTERM
78/79 func-thorough+func-arm-thorough+thorough -
qemu:func-arm-orangepi TIMEOUT 540.01s
killed by signal 15 SIGTERM
79/79 func-thorough+func-aarch64-thorough+thorough -
qemu:func-aarch64-sbsaref_freebsd TIMEOUT 720.02s
killed by signal 15 SIGTERM
I've kept the first 4 patches, but dropped patches 5-8.
I also noticed a problem with patch 5 which I've commented on.
thanks
-- PMM
^ permalink raw reply [flat|nested] 17+ messages in thread* Re: [PATCH v7 0/8] target/arm: fully model WFxT instructions for A-profile
2026-06-08 15:54 ` Peter Maydell
@ 2026-06-08 17:01 ` Alex Bennée
0 siblings, 0 replies; 17+ messages in thread
From: Alex Bennée @ 2026-06-08 17:01 UTC (permalink / raw)
To: Peter Maydell
Cc: qemu-devel, Paolo Bonzini, Alexander Graf, Mohamed Mediouni,
Pedro Barbuda, qemu-arm, kvm
Peter Maydell <peter.maydell@linaro.org> writes:
> On Mon, 8 Jun 2026 at 14:51, Peter Maydell <peter.maydell@linaro.org> wrote:
>>
>> On Fri, 29 May 2026 at 09:29, Alex Bennée <alex.bennee@linaro.org> wrote:
>> >
>> > 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 refactoring from the previous iterations of the patch have now
>> > been merged.
>> >
>> > I've dropped trying to fully model the global monitor in favour of
>> > taking advantage of the architectural flexibility to have an IMPDEF
>> > event wake up for any reason. We treat the setting of exclusive_addr
>> > as such a reason because it indicates the current vCPU is in a ldstx
>> > exclusive region and we don't want the guest to deadlock. This does mean
>> > the system won't sleep on WFE enabled locks but people shouldn't be
>> > relying on QEMU to model real world sleep patterns anyway given the
>> > efficiency of emulation compared to real HW.
>> >
>> > I've written a test case using kvm-unit-tests:
>> >
>> > Message-ID: <20260527111822.1563679-1-alex.bennee@linaro.org>
>> > Date: Wed, 27 May 2026 12:18:21 +0100
>> > Subject: [kvm-unit-tests PATCH v2] arm: add wfx test case
>> > From: =?UTF-8?q?Alex=20Benn=C3=A9e?= <alex.bennee@linaro.org>
>> >
>> > All patches are now reviewed.
>>
>>
>>
>> Applied to target-arm.next, thanks.
>
> This turns out to cause failures in "make check-functional": some
> tests now time out. It looks like the patch that triggers this
> is the "enable event stream on WFE instructions".
>
> 13/79 func-thorough+func-arm-thorough+thorough -
> qemu:func-arm-aspeed_rainier ERROR 36.17s
> exit status 1
> 74/79 func-thorough+func-arm-thorough+thorough -
> qemu:func-arm-smdkc210 TIMEOUT 90.01s
> killed by signal 15 SIGTERM
> 75/79 func-thorough+func-arm-thorough+thorough - qemu:func-arm-raspi2
> TIMEOUT 120.01s killed by signal 15
> SIGTERM
> 76/79 func-thorough+func-arm-thorough+thorough -
> qemu:func-arm-quanta_gsj TIMEOUT 240.01s
> killed by signal 15 SIGTERM
> 77/79 func-thorough+func-arm-thorough+thorough - qemu:func-arm-bpim2u
> TIMEOUT 500.01s killed by signal 15
> SIGTERM
> 78/79 func-thorough+func-arm-thorough+thorough -
> qemu:func-arm-orangepi TIMEOUT 540.01s
> killed by signal 15 SIGTERM
> 79/79 func-thorough+func-aarch64-thorough+thorough -
> qemu:func-aarch64-sbsaref_freebsd TIMEOUT 720.02s
> killed by signal 15 SIGTERM
>
>
> I've kept the first 4 patches, but dropped patches 5-8.
> I also noticed a problem with patch 5 which I've commented on.
OK I'll have a look.
>
> thanks
> -- PMM
--
Alex Bennée
Virtualisation Tech Lead @ Linaro
^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCH v7 0/8] target/arm: fully model WFxT instructions for A-profile
2026-06-08 13:51 ` [PATCH v7 0/8] target/arm: fully model WFxT instructions for A-profile Peter Maydell
2026-06-08 15:54 ` Peter Maydell
@ 2026-06-12 17:18 ` Alex Bennée
2026-06-12 17:46 ` Peter Maydell
1 sibling, 1 reply; 17+ messages in thread
From: Alex Bennée @ 2026-06-12 17:18 UTC (permalink / raw)
To: Peter Maydell
Cc: qemu-devel, Paolo Bonzini, Alexander Graf, Mohamed Mediouni,
Pedro Barbuda, qemu-arm, kvm
Peter Maydell <peter.maydell@linaro.org> writes:
> On Fri, 29 May 2026 at 09:29, Alex Bennée <alex.bennee@linaro.org> wrote:
>>
>> 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 refactoring from the previous iterations of the patch have now
>> been merged.
>>
>> I've dropped trying to fully model the global monitor in favour of
>> taking advantage of the architectural flexibility to have an IMPDEF
>> event wake up for any reason. We treat the setting of exclusive_addr
>> as such a reason because it indicates the current vCPU is in a ldstx
>> exclusive region and we don't want the guest to deadlock. This does mean
>> the system won't sleep on WFE enabled locks but people shouldn't be
>> relying on QEMU to model real world sleep patterns anyway given the
>> efficiency of emulation compared to real HW.
>>
>> I've written a test case using kvm-unit-tests:
>>
>> Message-ID: <20260527111822.1563679-1-alex.bennee@linaro.org>
>> Date: Wed, 27 May 2026 12:18:21 +0100
>> Subject: [kvm-unit-tests PATCH v2] arm: add wfx test case
>> From: =?UTF-8?q?Alex=20Benn=C3=A9e?= <alex.bennee@linaro.org>
>>
>> All patches are now reviewed.
>
>
>
> Applied to target-arm.next, thanks.
Is it too late to drop them? I've a fix for 2/8:
--8<---------------cut here---------------start------------->8---
modified include/hw/core/sysemu-cpu-ops.h
@@ -18,6 +18,9 @@
typedef struct SysemuCPUOps {
/**
* @has_work: Callback for checking if there is work to do.
+ *
+ * This function should be idempotent (i.e. not change state) as
+ * it will likely be queried multiple times before a CPU resumes.
*/
bool (*has_work)(CPUState *cpu); /* MANDATORY NON-NULL */
/**
modified target/arm/cpu.c
@@ -158,7 +158,6 @@ static bool arm_cpu_has_work(CPUState *cs)
* 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;
}
@@ -170,7 +169,6 @@ static bool arm_cpu_has_work(CPUState *cs)
| 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;
}
@@ -874,6 +872,8 @@ bool arm_cpu_exec_halt(CPUState *cs)
if (cpu->wfxt_timer) {
timer_del(cpu->wfxt_timer);
}
+ /* clear the halt reason */
+ cpu->env.halt_reason = NOT_HALTED;
}
return leave_halt;
}
--8<---------------cut here---------------end--------------->8---
>
> -- PMM
--
Alex Bennée
Virtualisation Tech Lead @ Linaro
^ permalink raw reply [flat|nested] 17+ messages in thread* Re: [PATCH v7 0/8] target/arm: fully model WFxT instructions for A-profile
2026-06-12 17:18 ` Alex Bennée
@ 2026-06-12 17:46 ` Peter Maydell
2026-06-12 18:50 ` Alex Bennée
0 siblings, 1 reply; 17+ messages in thread
From: Peter Maydell @ 2026-06-12 17:46 UTC (permalink / raw)
To: Alex Bennée
Cc: qemu-devel, Paolo Bonzini, Alexander Graf, Mohamed Mediouni,
Pedro Barbuda, qemu-arm, kvm
On Fri, 12 Jun 2026 at 18:18, Alex Bennée <alex.bennee@linaro.org> wrote:
>
> Peter Maydell <peter.maydell@linaro.org> writes:
>
> > On Fri, 29 May 2026 at 09:29, Alex Bennée <alex.bennee@linaro.org> wrote:
> >>
> >> 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 refactoring from the previous iterations of the patch have now
> >> been merged.
> >>
> >> I've dropped trying to fully model the global monitor in favour of
> >> taking advantage of the architectural flexibility to have an IMPDEF
> >> event wake up for any reason. We treat the setting of exclusive_addr
> >> as such a reason because it indicates the current vCPU is in a ldstx
> >> exclusive region and we don't want the guest to deadlock. This does mean
> >> the system won't sleep on WFE enabled locks but people shouldn't be
> >> relying on QEMU to model real world sleep patterns anyway given the
> >> efficiency of emulation compared to real HW.
> >>
> >> I've written a test case using kvm-unit-tests:
> >>
> >> Message-ID: <20260527111822.1563679-1-alex.bennee@linaro.org>
> >> Date: Wed, 27 May 2026 12:18:21 +0100
> >> Subject: [kvm-unit-tests PATCH v2] arm: add wfx test case
> >> From: =?UTF-8?q?Alex=20Benn=C3=A9e?= <alex.bennee@linaro.org>
> >>
> >> All patches are now reviewed.
> >
> >
> >
> > Applied to target-arm.next, thanks.
>
> Is it too late to drop them? I've a fix for 2/8:
That change is already in upstream git, so you'll need to
send the fix as a standalone patch, I'm afraid.
-- PMM
^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCH v7 0/8] target/arm: fully model WFxT instructions for A-profile
2026-06-12 17:46 ` Peter Maydell
@ 2026-06-12 18:50 ` Alex Bennée
0 siblings, 0 replies; 17+ messages in thread
From: Alex Bennée @ 2026-06-12 18:50 UTC (permalink / raw)
To: Peter Maydell
Cc: qemu-devel, Paolo Bonzini, Alexander Graf, Mohamed Mediouni,
Pedro Barbuda, qemu-arm, kvm
Peter Maydell <peter.maydell@linaro.org> writes:
> On Fri, 12 Jun 2026 at 18:18, Alex Bennée <alex.bennee@linaro.org> wrote:
>>
>> Peter Maydell <peter.maydell@linaro.org> writes:
>>
>> > On Fri, 29 May 2026 at 09:29, Alex Bennée <alex.bennee@linaro.org> wrote:
>> >>
>> >> 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 refactoring from the previous iterations of the patch have now
>> >> been merged.
>> >>
>> >> I've dropped trying to fully model the global monitor in favour of
>> >> taking advantage of the architectural flexibility to have an IMPDEF
>> >> event wake up for any reason. We treat the setting of exclusive_addr
>> >> as such a reason because it indicates the current vCPU is in a ldstx
>> >> exclusive region and we don't want the guest to deadlock. This does mean
>> >> the system won't sleep on WFE enabled locks but people shouldn't be
>> >> relying on QEMU to model real world sleep patterns anyway given the
>> >> efficiency of emulation compared to real HW.
>> >>
>> >> I've written a test case using kvm-unit-tests:
>> >>
>> >> Message-ID: <20260527111822.1563679-1-alex.bennee@linaro.org>
>> >> Date: Wed, 27 May 2026 12:18:21 +0100
>> >> Subject: [kvm-unit-tests PATCH v2] arm: add wfx test case
>> >> From: =?UTF-8?q?Alex=20Benn=C3=A9e?= <alex.bennee@linaro.org>
>> >>
>> >> All patches are now reviewed.
>> >
>> >
>> >
>> > Applied to target-arm.next, thanks.
>>
>> Is it too late to drop them? I've a fix for 2/8:
>
> That change is already in upstream git, so you'll need to
> send the fix as a standalone patch, I'm afraid.
No worries, I'll fix it up in the re-base.
>
> -- PMM
--
Alex Bennée
Virtualisation Tech Lead @ Linaro
^ permalink raw reply [flat|nested] 17+ messages in thread