On Wed, 21 Jan 2026 at 13:27, Ashish Anand <[email protected]> wrote:
>
> Currently, QEMU implements the 'Wait For Event' (WFE) instruction as a
> simple yield. This causes high host CPU usage because guest
> RTOS idle loops effectively become busy-wait loops.
>
> To improve efficiency, this patch transitions WFE to use the architectural
> 'Halt' state (EXCP_HLT) for M-profile CPUs. This allows the host thread
> to sleep when the guest is idle.
>
> To support this transition, we implement the full architectural behavior
> required for WFE, specifically the 'Event Register', 'SEVONPEND' logic,
> and 'R_BPBR' exception handling requirements defined in the ARM
> Architecture Reference Manual.
>
> This patch enables resource-efficient idle emulation for Cortex-M.
>
> Signed-off-by: Ashish Anand <[email protected]>
> ---
> Changes in v2:
> 1. Added R_BPBR handling as required by the Armv8-M architecture.
> 2. Unified pending-state updates to detect interrupt transitions for 
> SEVONPEND.
> 3. Moved the Event Register to the top-level ARM CPU state, since it is
>    architecturally shared between A-profile and M-profile CPUs.
> 4. Updated migration handling to be profile-agnostic so the state can be
>    reused if A-profile WFE support is implemented in the future.
> 5. Added CONFIG_USER_ONLY handling for WFE/SEV and tightened profile checks.
> 6. Addressed review comments and fixes raised during v1 discussion.
>
> Link to v1 - 
> https://lore.kernel.org/qemu-devel/[email protected]/
>
>
>  hw/intc/armv7m_nvic.c      | 85 ++++++++++++++++++++++++++++++--------
>  target/arm/cpu.c           |  6 +++
>  target/arm/cpu.h           |  7 ++++
>  target/arm/machine.c       | 19 +++++++++
>  target/arm/tcg/helper.h    |  1 +
>  target/arm/tcg/m_helper.c  |  5 +++
>  target/arm/tcg/op_helper.c | 56 +++++++++++++++++++++----
>  target/arm/tcg/t16.decode  |  5 ++-
>  target/arm/tcg/t32.decode  |  5 ++-
>  target/arm/tcg/translate.c | 29 +++++++++++--
>  10 files changed, 185 insertions(+), 33 deletions(-)
>
> diff --git a/hw/intc/armv7m_nvic.c b/hw/intc/armv7m_nvic.c
> index 3a31eb56f3..854d27e413 100644
> --- a/hw/intc/armv7m_nvic.c
> +++ b/hw/intc/armv7m_nvic.c
> @@ -221,6 +221,40 @@ static int exc_group_prio(NVICState *s, int rawprio, 
> bool targets_secure)
>      return rawprio;
>  }
>
> +/*
> + * Update the pending state of an exception vector.
> + * This is the central function for all updates to vec->pending.
> + * Handles SEVONPEND: if this is a 0->1 transition on an external interrupt
> + * and SEVONPEND is set in the appropriate SCR, sets the event register.
> + */
> +static void nvic_update_pending_state(NVICState *s, int irq, bool secure,
> +                                      uint8_t next_pending_val)
> +{
> +    VecInfo *vec;
> +    int scr_bank;
> +    uint8_t prev_pending_val;
> +
> +    if (secure && exc_is_banked(irq)) {
> +        vec = &s->sec_vectors[irq];
> +        scr_bank = M_REG_S;
> +    } else {
> +        vec = &s->vectors[irq];
> +        scr_bank = M_REG_NS;
> +    }

You already have the VecInfo pointer at all the callsites,
so I think it would be better to pass it to this function
rather than recalculating it from the irq number etc.

I agree with Alex about using a bool for the event_register
struct field.

Otherwise I think this looks good!

thanks
-- PMM

Reply via email to