All of lore.kernel.org
 help / color / mirror / Atom feed
* [RFC PATCH] target/arm: hold bql when SEV sets the event_register
@ 2026-10-12 13:48 Alex Bennée
  2026-10-12 14:52 ` Alex Bennée
  2026-10-13 11:41 ` Peter Maydell
  0 siblings, 2 replies; 6+ messages in thread
From: Alex Bennée @ 2026-10-12 13:48 UTC (permalink / raw)
  To: qemu-devel
  Cc: Alex Bennée, Paolo Bonzini, Richard Henderson,
	Philippe Mathieu-Daudé, Peter Maydell,
	open list:ARM TCG CPUs

There is a race in qemu_process_cpu_events and sleeping on halt_cond
where we can miss the setting of the event_register which would cause
arm_cpu_has_work to report we shouldn't sleep. As by definition the
bql has to be held when we go to sleep against halt_cond guard the
kicking of the cpus by the SEV helper with the BQL to ensure things
are properly serialised.

The other places that set event_register are fine as they are either
in the same vCPU context or are already serialised by the BQL.

Also use qemu_cond_wait_bql like the other halt_cond users.

Resolves: https://gitlab.com/qemu-project/qemu/-/work_items/4660
Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
---
 system/cpus.c              | 2 +-
 target/arm/tcg/op_helper.c | 3 +++
 2 files changed, 4 insertions(+), 1 deletion(-)

diff --git a/system/cpus.c b/system/cpus.c
index e11a5aab6a6..985732217fb 100644
--- a/system/cpus.c
+++ b/system/cpus.c
@@ -412,7 +412,7 @@ void qemu_process_cpu_events(CPUState *cpu)
             slept = true;
             qemu_plugin_vcpu_idle_cb(cpu);
         }
-        qemu_cond_wait(cpu->halt_cond, &bql);
+        qemu_cond_wait_bql(cpu->halt_cond);
     }
     if (slept) {
         qemu_plugin_vcpu_resume_cb(cpu);
diff --git a/target/arm/tcg/op_helper.c b/target/arm/tcg/op_helper.c
index af56eff9f18..7c1fdab79d7 100644
--- a/target/arm/tcg/op_helper.c
+++ b/target/arm/tcg/op_helper.c
@@ -471,6 +471,9 @@ void HELPER(wfit)(CPUARMState *env, uint32_t rd)
 void HELPER(sev)(CPUARMState *env)
 {
     CPUState *cs = env_cpu(env);
+
+    BQL_LOCK_GUARD();
+
     CPU_FOREACH(cs) {
         ARMCPU *target_cpu = ARM_CPU(cs);
         target_cpu->env.event_register = true;
-- 
2.47.3



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

* Re: [RFC PATCH] target/arm: hold bql when SEV sets the event_register
  2026-10-12 13:48 [RFC PATCH] target/arm: hold bql when SEV sets the event_register Alex Bennée
@ 2026-10-12 14:52 ` Alex Bennée
  2026-10-12 16:27   ` Paolo Bonzini
  2026-10-13 11:41 ` Peter Maydell
  1 sibling, 1 reply; 6+ messages in thread
From: Alex Bennée @ 2026-10-12 14:52 UTC (permalink / raw)
  To: qemu-devel
  Cc: Paolo Bonzini, Richard Henderson, Philippe Mathieu-Daudé,
	Peter Maydell, open list:ARM TCG CPUs

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

> There is a race in qemu_process_cpu_events and sleeping on halt_cond
> where we can miss the setting of the event_register which would cause
> arm_cpu_has_work to report we shouldn't sleep. As by definition the
> bql has to be held when we go to sleep against halt_cond guard the
> kicking of the cpus by the SEV helper with the BQL to ensure things
> are properly serialised.
>
> The other places that set event_register are fine as they are either
> in the same vCPU context or are already serialised by the BQL.
>
> Also use qemu_cond_wait_bql like the other halt_cond users.
>
> Resolves: https://gitlab.com/qemu-project/qemu/-/work_items/4660

This also fixes 4670 

> Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
> ---
>  system/cpus.c              | 2 +-
>  target/arm/tcg/op_helper.c | 3 +++
>  2 files changed, 4 insertions(+), 1 deletion(-)
>
> diff --git a/system/cpus.c b/system/cpus.c
> index e11a5aab6a6..985732217fb 100644
> --- a/system/cpus.c
> +++ b/system/cpus.c
> @@ -412,7 +412,7 @@ void qemu_process_cpu_events(CPUState *cpu)
>              slept = true;
>              qemu_plugin_vcpu_idle_cb(cpu);
>          }
> -        qemu_cond_wait(cpu->halt_cond, &bql);
> +        qemu_cond_wait_bql(cpu->halt_cond);
>      }
>      if (slept) {
>          qemu_plugin_vcpu_resume_cb(cpu);
> diff --git a/target/arm/tcg/op_helper.c b/target/arm/tcg/op_helper.c
> index af56eff9f18..7c1fdab79d7 100644
> --- a/target/arm/tcg/op_helper.c
> +++ b/target/arm/tcg/op_helper.c
> @@ -471,6 +471,9 @@ void HELPER(wfit)(CPUARMState *env, uint32_t rd)
>  void HELPER(sev)(CPUARMState *env)
>  {
>      CPUState *cs = env_cpu(env);
> +
> +    BQL_LOCK_GUARD();
> +
>      CPU_FOREACH(cs) {
>          ARMCPU *target_cpu = ARM_CPU(cs);
>          target_cpu->env.event_register = true;

-- 
Alex Bennée
Virtualisation Tech Lead @ Linaro


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

* Re: [RFC PATCH] target/arm: hold bql when SEV sets the event_register
  2026-10-12 14:52 ` Alex Bennée
@ 2026-10-12 16:27   ` Paolo Bonzini
  2026-10-12 18:47     ` Alex Bennée
  0 siblings, 1 reply; 6+ messages in thread
From: Paolo Bonzini @ 2026-10-12 16:27 UTC (permalink / raw)
  To: Alex Bennée, qemu-devel
  Cc: Richard Henderson, Philippe Mathieu-Daudé, Peter Maydell,
	open list:ARM TCG CPUs

On 10/12/26 16:52, Alex Bennée wrote:
>> diff --git a/target/arm/tcg/op_helper.c b/target/arm/tcg/op_helper.c
>> index af56eff9f18..7c1fdab79d7 100644
>> --- a/target/arm/tcg/op_helper.c
>> +++ b/target/arm/tcg/op_helper.c
>> @@ -471,6 +471,9 @@ void HELPER(wfit)(CPUARMState *env, uint32_t rd)
>>   void HELPER(sev)(CPUARMState *env)
>>   {
>>       CPUState *cs = env_cpu(env);
>> +
>> +    BQL_LOCK_GUARD();
>> +
>>       CPU_FOREACH(cs) {
>>           ARMCPU *target_cpu = ARM_CPU(cs);
>>           target_cpu->env.event_register = true;
Reviewed-by: Paolo Bonzini <pbonzini@redhat.com>

The use of cmpxchg in wfxt_timer_cb is fishy though.

Clearing HALT_WFE should be the task of the target CPU, not the timer. 
The timer_mod() should be *after* halt_reason(*), and then you can just 
do a qatomic_read() instead of a cmpxchg(**) in wfxt_timer_cb().

However, I don't understand at all why wfxt_timer_cb needs to set 
event_register to true.  It seems to me that a wfet + wfe sequence, 
where the first wfet times out, *should* halt again on the second wfe; 
but as the code is written it doesn't.

I think wfxt_timer_cb only needs to call cpu_interrupt().

Thanks,

Paolo

(*) always, even if the halt reason is not HALT_WFE, if only for consistency

(**) you don't need a lock or acquire/release here, because the timer 
callback always sees everything that happened before timer_mod().  In a 
sense, timer_mod() *is* the release operation and starting the callback 
is the acquire operation.



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

* Re: [RFC PATCH] target/arm: hold bql when SEV sets the event_register
  2026-10-12 16:27   ` Paolo Bonzini
@ 2026-10-12 18:47     ` Alex Bennée
  2026-10-13  5:13       ` Paolo Bonzini
  0 siblings, 1 reply; 6+ messages in thread
From: Alex Bennée @ 2026-10-12 18:47 UTC (permalink / raw)
  To: Paolo Bonzini
  Cc: qemu-devel, Richard Henderson, Philippe Mathieu-Daudé,
	Peter Maydell, open list:ARM TCG CPUs

Paolo Bonzini <pbonzini@redhat.com> writes:

> On 10/12/26 16:52, Alex Bennée wrote:
>>> diff --git a/target/arm/tcg/op_helper.c b/target/arm/tcg/op_helper.c
>>> index af56eff9f18..7c1fdab79d7 100644
>>> --- a/target/arm/tcg/op_helper.c
>>> +++ b/target/arm/tcg/op_helper.c
>>> @@ -471,6 +471,9 @@ void HELPER(wfit)(CPUARMState *env, uint32_t rd)
>>>   void HELPER(sev)(CPUARMState *env)
>>>   {
>>>       CPUState *cs = env_cpu(env);
>>> +
>>> +    BQL_LOCK_GUARD();
>>> +
>>>       CPU_FOREACH(cs) {
>>>           ARMCPU *target_cpu = ARM_CPU(cs);
>>>           target_cpu->env.event_register = true;
> Reviewed-by: Paolo Bonzini <pbonzini@redhat.com>
>
> The use of cmpxchg in wfxt_timer_cb is fishy though.
>
> Clearing HALT_WFE should be the task of the target CPU, not the timer.
> The timer_mod() should be *after* halt_reason(*), and then you can
> just do a qatomic_read() instead of a cmpxchg(**) in wfxt_timer_cb().
>
> However, I don't understand at all why wfxt_timer_cb needs to set
> event_register to true.  It seems to me that a wfet + wfe sequence,
> where the first wfet times out, *should* halt again on the second wfe;
> but as the code is written it doesn't.
>
> I think wfxt_timer_cb only needs to call cpu_interrupt().

Something like:

--8<---------------cut here---------------start------------->8---
modified    target/arm/cpu.c
@@ -877,25 +877,22 @@ bool arm_cpu_exec_halt(CPUState *cs)
     bool leave_halt = cpu_has_work(cs);
 
     if (leave_halt) {
-        /* We're about to come out of WFI/WFE: disable the WFxT timer */
         ARMCPU *cpu = ARM_CPU(cs);
+
+        qatomic_set(&cpu->env.halt_reason, NOT_HALTED);
+
         if (cpu->wfxt_timer) {
             timer_del(cpu->wfxt_timer);
         }
-        /* clear the halt reason */
-        qatomic_set(&cpu->env.halt_reason, NOT_HALTED);
     }
     return leave_halt;
 }
 #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.
+ * Unlike almost everything else that messes with the halt_reason the
+ * timer callbacks are not in the vCPU context so we must use atomics
+ * to check it.
  */
 static void arm_wfxt_timer_cb(void *opaque)
 {
@@ -903,17 +900,15 @@ static void arm_wfxt_timer_cb(void *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);
+    if (qatomic_read(&env->halt_reason) == HALT_WFE) {
+        /*
+         * We expect the CPU to be halted; this will cause arm_cpu_is_work()
+         * to return true (so we will come out of halt even with no other
+         * pending interrupt), and the TCG accelerator's cpu_exec_interrupt()
+         * function auto-clears the CPU_INTERRUPT_EXITTB flag for us.
+         */
+        cpu_interrupt(cs, CPU_INTERRUPT_EXITTB);
     }
-
-    /*
-     * We expect the CPU to be halted; this will cause arm_cpu_is_work()
-     * to return true (so we will come out of halt even with no other
-     * pending interrupt), and the TCG accelerator's cpu_exec_interrupt()
-     * function auto-clears the CPU_INTERRUPT_EXITTB flag for us.
-     */
-    cpu_interrupt(cs, CPU_INTERRUPT_EXITTB);
 }
 #endif
--8<---------------cut here---------------end--------------->8---

?

>
> Thanks,
>
> Paolo
>
> (*) always, even if the halt reason is not HALT_WFE, if only for consistency
>
> (**) you don't need a lock or acquire/release here, because the timer
> callback always sees everything that happened before timer_mod().  In
> a sense, timer_mod() *is* the release operation and starting the
> callback is the acquire operation.

-- 
Alex Bennée
Virtualisation Tech Lead @ Linaro


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

* Re: [RFC PATCH] target/arm: hold bql when SEV sets the event_register
  2026-10-12 18:47     ` Alex Bennée
@ 2026-10-13  5:13       ` Paolo Bonzini
  0 siblings, 0 replies; 6+ messages in thread
From: Paolo Bonzini @ 2026-10-13  5:13 UTC (permalink / raw)
  To: Alex Bennée
  Cc: qemu-devel, Richard Henderson, Philippe Mathieu-Daudé,
	Peter Maydell, open list:ARM TCG CPUs

[-- Attachment #1: Type: text/plain, Size: 3081 bytes --]

Il lun 12 ott 2026, 20:47 Alex Bennée <alex.bennee@linaro.org> ha scritto:

> Paolo Bonzini <pbonzini@redhat.com> writes:
>
>
> > I think wfxt_timer_cb only needs to call cpu_interrupt().
>
> Something like:
>

No, the cpu_interrupt must be unconditional due to the WFIT instruction.
Your patch puts it under qatomic_read(&env->halt_reason) == HALT_WFE.

>
> +
> +        qatomic_set(&cpu->env.halt_reason, NOT_HALTED);
> +
>          if (cpu->wfxt_timer) {
>              timer_del(cpu->wfxt_timer);
>          }
> -        /* clear the halt reason */
> -        qatomic_set(&cpu->env.halt_reason, NOT_HALTED);
>

I was thinking about the ordering before timer_mod, in the
wfe/wfi/wfet/wfit helpers. However it is not relevant if the timer callback
does not check halt_reason.

Paolo

     }
>      return leave_halt;
>  }
>  #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.
> + * Unlike almost everything else that messes with the halt_reason the
> + * timer callbacks are not in the vCPU context so we must use atomics
> + * to check it.
>   */
>  static void arm_wfxt_timer_cb(void *opaque)
>  {
> @@ -903,17 +900,15 @@ static void arm_wfxt_timer_cb(void *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);
> +    if (qatomic_read(&env->halt_reason) == HALT_WFE) {
> +        /*
> +         * We expect the CPU to be halted; this will cause
> arm_cpu_is_work()
> +         * to return true (so we will come out of halt even with no other
> +         * pending interrupt), and the TCG accelerator's
> cpu_exec_interrupt()
> +         * function auto-clears the CPU_INTERRUPT_EXITTB flag for us.
> +         */
> +        cpu_interrupt(cs, CPU_INTERRUPT_EXITTB);
>      }
> -
> -    /*
> -     * We expect the CPU to be halted; this will cause arm_cpu_is_work()
> -     * to return true (so we will come out of halt even with no other
> -     * pending interrupt), and the TCG accelerator's cpu_exec_interrupt()
> -     * function auto-clears the CPU_INTERRUPT_EXITTB flag for us.
> -     */
> -    cpu_interrupt(cs, CPU_INTERRUPT_EXITTB);
>  }
>  #endif
> --8<---------------cut here---------------end--------------->8---
>
> ?
>
> >
> > Thanks,
> >
> > Paolo
> >
> > (*) always, even if the halt reason is not HALT_WFE, if only for
> consistency
> >
> > (**) you don't need a lock or acquire/release here, because the timer
> > callback always sees everything that happened before timer_mod().  In
> > a sense, timer_mod() *is* the release operation and starting the
> > callback is the acquire operation.
>
> --
> Alex Bennée
> Virtualisation Tech Lead @ Linaro
>
>

[-- Attachment #2: Type: text/html, Size: 4419 bytes --]

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

* Re: [RFC PATCH] target/arm: hold bql when SEV sets the event_register
  2026-10-12 13:48 [RFC PATCH] target/arm: hold bql when SEV sets the event_register Alex Bennée
  2026-10-12 14:52 ` Alex Bennée
@ 2026-10-13 11:41 ` Peter Maydell
  1 sibling, 0 replies; 6+ messages in thread
From: Peter Maydell @ 2026-10-13 11:41 UTC (permalink / raw)
  To: Alex Bennée
  Cc: qemu-devel, Paolo Bonzini, Richard Henderson,
	Philippe Mathieu-Daudé, open list:ARM TCG CPUs

On Mon, 12 Oct 2026 at 14:48, Alex Bennée <alex.bennee@linaro.org> wrote:
>
> There is a race in qemu_process_cpu_events and sleeping on halt_cond
> where we can miss the setting of the event_register which would cause
> arm_cpu_has_work to report we shouldn't sleep. As by definition the
> bql has to be held when we go to sleep against halt_cond guard the
> kicking of the cpus by the SEV helper with the BQL to ensure things
> are properly serialised.
>
> The other places that set event_register are fine as they are either
> in the same vCPU context or are already serialised by the BQL.
>
> Also use qemu_cond_wait_bql like the other halt_cond users.
>
> Resolves: https://gitlab.com/qemu-project/qemu/-/work_items/4660
> Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
> ---
>  system/cpus.c              | 2 +-
>  target/arm/tcg/op_helper.c | 3 +++
>  2 files changed, 4 insertions(+), 1 deletion(-)

This should be

Cc: qemu-stable@nongnu.org
Fixes: d238858bff6 ("target/arm: Implement WFE, SEV and SEVONPEND for Cortex-M")

right?

thanks
-- PMM


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

end of thread, other threads:[~2026-10-13 11:42 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-10-12 13:48 [RFC PATCH] target/arm: hold bql when SEV sets the event_register Alex Bennée
2026-10-12 14:52 ` Alex Bennée
2026-10-12 16:27   ` Paolo Bonzini
2026-10-12 18:47     ` Alex Bennée
2026-10-13  5:13       ` Paolo Bonzini
2026-10-13 11:41 ` Peter Maydell

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