From: "Scott J. Goldman" <scottjgo@gmail.com>
To: "Peter Maydell" <peter.maydell@linaro.org>,
"Scott J. Goldman" <scottjgo@gmail.com>
Cc: <qemu-devel@nongnu.org>, <qemu-arm@nongnu.org>,
<rbolshakov@ddn.com>, <phil@philjordan.eu>, <agraf@csgraf.de>
Subject: Re: [PATCH v2] target/arm/hvf: Fix WFI halting to stop idle vCPU spinning
Date: Mon, 27 Apr 2026 11:42:23 -0700 [thread overview]
Message-ID: <DI45PH4NASOO.3MQVHIFL83QFX@gmail.com> (raw)
In-Reply-To: <CAFEAcA9RHQ+7++=kLn2goJwcgzDnaqdkQtQBtxQ2Rw1-uiKY=g@mail.gmail.com>
On Mon Apr 27, 2026 at 4:15 AM PDT, Peter Maydell wrote:
> On Fri, 10 Apr 2026 at 06:50, Scott J. Goldman <scottjgo@gmail.com> wrote:
>>
>> Commit b5f8f77271 ("accel/hvf: Implement WFI without using pselect()")
>> changed hvf_wfi() from blocking the vCPU thread with pselect() to
>> returning EXCP_HLT, intending QEMU's main event loop to handle the
>> idle wait. However, cpu->halted was never set, so cpu_thread_is_idle()
>> always returns false and the vCPU thread spins at 100% CPU per core
>> while the guest is idle.
>>
>> Fix this by:
>>
>> 1. Setting cpu->halted = 1 in hvf_wfi() so the vCPU thread sleeps on
>> halt_cond in qemu_process_cpu_events().
>>
>> 2. Arming a host-side QEMU_CLOCK_HOST timer to fire when the guest's
>> virtual timer (CNTV_CVAL_EL0) would expire. This is necessary
>> because HVF only delivers HV_EXIT_REASON_VTIMER_ACTIVATED during
>> hv_vcpu_run(), which is not called while the CPU is halted. The
>> timer callback mirrors the VTIMER_ACTIVATED handler: it raises the
>> vtimer IRQ through the GIC and marks vtimer_masked, causing the
>> interrupt delivery chain to wake the vCPU via qemu_cpu_kick().
>
> A host side timer here seems a bit odd -- it will still
> expire even if the user halts the whole VM. We only use
> QEMU_CLOCK_HOST timers for things that are part of QEMU proper,
> like handling timeouts in the migration networking code.
>
>> diff --git a/include/system/hvf_int.h b/include/system/hvf_int.h
>> index 2621164cb2..58fb865eba 100644
>> --- a/include/system/hvf_int.h
>> +++ b/include/system/hvf_int.h
>> @@ -48,6 +48,7 @@ struct AccelCPUState {
>> hv_vcpu_exit_t *exit;
>> bool vtimer_masked;
>> bool guest_debug_enabled;
>> + struct QEMUTimer *wfi_timer;
>> #endif
>> };
>
> QEMUTimer objects need to be migrated. I think as it is now,
> if you do a migration while one vCPU is in WFI we won't
> migrate the timer state, and so on the destination it won't
> be woken up when it should.
Hi Peter--
Thanks for the review here. I am going to post a follow-up patch based
on your comments, but I did want to just flag that migration is broken
in hvf/arm right now (segfaults in the dirty page tracking code). Of
course, I can post fixes for that as well.
>
>> +static void hvf_wfi_timer_cb(void *opaque)
>> +{
>> + CPUState *cpu = opaque;
>> + ARMCPU *arm_cpu = ARM_CPU(cpu);
>> +
>> + /*
>> + * vtimer expired while the CPU was halted for WFI.
>> + * Mirror HV_EXIT_REASON_VTIMER_ACTIVATED: raise the vtimer
>> + * interrupt and mark as masked so hvf_sync_vtimer() will
>> + * check and unmask when the guest handles it.
>> + *
>> + * The interrupt delivery chain (GIC -> cpu_interrupt ->
>> + * qemu_cpu_kick) wakes the vCPU thread from halt_cond.
>> + */
>> + qemu_set_irq(arm_cpu->gt_timer_outputs[GTIMER_VIRT], 1);
>> + cpu->accel->vtimer_masked = true;
>
> If the VM happens to be stopped by the user when the timer
> fires, this will change the VM state, which I suspect is
> not correct. Avoiding use of a QEMU_CLOCK_HOST timer would
> fix this.
>
>> +}
>> +
>> static int hvf_wfi(CPUState *cpu)
>> {
>> + ARMCPU *arm_cpu = ARM_CPU(cpu);
>> + uint64_t ctl, cval;
>> + hv_return_t r;
>> +
>> if (cpu_has_work(cpu)) {
>> /*
>> * Don't bother to go into our "low power state" if
>> @@ -2037,6 +2068,34 @@ static int hvf_wfi(CPUState *cpu)
>> return 0;
>> }
>>
>> + /*
>> + * Set up a host-side timer to wake us when the vtimer expires.
>> + * HVF only delivers HV_EXIT_REASON_VTIMER_ACTIVATED during
>> + * hv_vcpu_run(), which we won't call while halted.
>> + */
>> + r = hv_vcpu_get_sys_reg(cpu->accel->fd, HV_SYS_REG_CNTV_CTL_EL0, &ctl);
>> + assert_hvf_ok(r);
>> +
>> + if ((ctl & TMR_CTL_ENABLE) && !(ctl & TMR_CTL_IMASK)) {
>> + r = hv_vcpu_get_sys_reg(cpu->accel->fd,
>> + HV_SYS_REG_CNTV_CVAL_EL0, &cval);
>> + assert_hvf_ok(r);
>> +
>> + uint64_t now = hvf_vtimer_val_raw();
>> + if (cval <= now) {
>> + /* Timer already expired, don't halt */
>> + return 0;
>> + }
>> +
>> + uint64_t delta_ticks = cval - now;
>> + int64_t delta_ns = delta_ticks * NANOSECONDS_PER_SECOND
>> + / arm_cpu->gt_cntfrq_hz;
>
> As a general rule, tick-to-ns and vice-versa conversions should
> use muldiv64() to avoid potential overflow in the intermediate value.
>
>> + int64_t deadline = qemu_clock_get_ns(QEMU_CLOCK_HOST) + delta_ns;
>> +
>> + timer_mod(cpu->accel->wfi_timer, deadline);
>> + }
>> +
>> + cpu->halted = 1;
>> return EXCP_HLT;
>> }
>
> thanks
> -- PMM
next prev parent reply other threads:[~2026-04-27 18:42 UTC|newest]
Thread overview: 22+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-04-10 4:47 [PATCH] target/arm/hvf: Fix WFI halting to stop idle vCPU spinning Scott J. Goldman
2026-04-10 5:06 ` Mohamed Mediouni
2026-04-10 5:28 ` Scott J. Goldman
2026-04-10 5:50 ` [PATCH v2] " Scott J. Goldman
2026-04-10 6:18 ` Mohamed Mediouni
2026-04-16 21:20 ` Scott J. Goldman
2026-04-17 9:57 ` Philippe Mathieu-Daudé
2026-04-17 20:30 ` Scott J. Goldman
2026-04-21 23:24 ` Scott J. Goldman
2026-04-27 11:15 ` Peter Maydell
2026-04-27 18:42 ` Scott J. Goldman [this message]
2026-04-27 19:55 ` [PATCH v3] " Scott J. Goldman
2026-05-12 16:46 ` Scott J. Goldman
2026-05-12 19:18 ` Peter Maydell
2026-05-12 17:54 ` Mohamed Mediouni
2026-05-12 20:36 ` Scott J. Goldman
2026-05-12 20:51 ` Mohamed Mediouni
2026-05-13 1:21 ` Mohamed Mediouni
2026-05-13 2:21 ` [PATCH v11.1+ v4] " Scott J. Goldman
2026-05-15 10:39 ` Peter Maydell
2026-05-13 2:25 ` [PATCH v3] " Scott J. Goldman
2026-05-13 7:14 ` Mohamed Mediouni
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=DI45PH4NASOO.3MQVHIFL83QFX@gmail.com \
--to=scottjgo@gmail.com \
--cc=agraf@csgraf.de \
--cc=peter.maydell@linaro.org \
--cc=phil@philjordan.eu \
--cc=qemu-arm@nongnu.org \
--cc=qemu-devel@nongnu.org \
--cc=rbolshakov@ddn.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
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.