RISC-V WFI: Recheck Work After Wake Without Assuming an Interrupt Was Taken

A RISC-V idle loop executes WFI, returns to the next instruction, and finds that its interrupt-handler counter has not changed. That observation alone does not indicate broken hardware. The instruction’s completion and the delivery of an interrupt are separate architectural questions.

This discussion pins the Machine-Level ISA, version 1.13, in the January 2026 specification library, especially section 2.1.3.3. It concerns ordinary machine and supervisor execution without virtualization. It does not define a board’s power-state entry protocol or a complete scheduler idle algorithm.

Interpret WFI as permission to stall

WFI tells the implementation that the hart can stall until an interrupt might need service. It does not promise a minimum residence time or a particular low-power state. The specification permits execution to resume for any reason, even without an enabled interrupt becoming pending. Implementing the instruction as a no-operation is legal.

Therefore, neither a fast return nor an unchanged handler counter proves that the instruction was ignored incorrectly. Conversely, executing it repeatedly does not demonstrate that clocks, voltage domains or peripheral power have changed. Those claims need the platform’s separate power-management contract and actual measurements.

The useful software invariant is simpler: after the idle instruction, reevaluate the condition that justified idling. If actionable work exists, take the appropriate path. If it does not, the loop may wait again under the operating system’s established synchronization rules.

Separate local enable from global enable

The wake rules must be unaffected by the global interrupt-enable bits mstatus.MIE and mstatus.SIE, and by interrupt delegation through mideleg. A locally enabled pending interrupt must make the hart resume, including one delegated to a less-privileged mode. Whether that source can immediately take a trap is a different predicate.

Consider an illustrative M-mode case with a machine interrupt pending and its individual enable set, but MIE=0. WFI must resume for that locally enabled source. The cleared global bit still prevents that same-mode interrupt from being taken at that point. Reaching the instruction after WFI without entering the handler is consistent with the architecture.

If that interrupt instead becomes eligible for delivery, execution can enter its handler. The specification describes the interrupt trap at the following instruction, with mepc=pc+4 for machine-mode handling. A normal return then reaches the code after the wait instruction. Do not treat that saved program counter as evidence that the wait itself faulted.

Rule matrix separating WFI resumption from interrupt delivery for pending, individually enabled and globally enabled machine interrupts.
Original architectural rule matrix. A legal return from WFI does not prove that an interrupt handler ran.

Keep the weaker individual-enable rule weaker

For individually disabled interrupts, the specification says implementations should honor the individual enables, for example MTIE, and avoid resuming for a source that is pending but not individually enabled. That is a “should,” not a guarantee that every such source leaves the hart asleep.

The general permission to resume for any reason still matters. A diagnostic matrix should therefore distinguish “required to resume” from “allowed to resume.” It should not label the absence of a locally enabled source as a guaranteed sleeping state. A test that assumes that guarantee would reject a legal no-operation implementation.

After a wake without a trap, firmware can inspect the relevant pending state, such as mip or sip, where the execution environment permits it. It must still decide whether that state represents useful work for this layer. A pending delegated source, an application work flag and a completed interrupt handler are different observations.

Check execution permission before diagnosing wake behavior

The mstatus.TW field adds another boundary. In less-privileged modes, TW=1 can cause an illegal-instruction exception if the wait does not complete within an implementation-specific bounded interval. An implementation may trap immediately in that situation.

That exception is an interception of the instruction, not proof that the expected device interrupted the hart. Record the actual trap cause and execution mode before treating every departure from the idle path as an ordinary wake. This article deliberately does not extend the matrix to virtualized guests or optional user-mode execution.

Make the review record explain both outcomes

For a proposed firmware review, record the pending source, individual enable, current privilege, applicable global enable, delegation and observed return path. Then answer two questions independently: must the wait resume, and is an interrupt trap eligible now?

Also inspect how the existing idle protocol prevents work from arriving between its last work check and its wait decision. Merely adding a post-wake check is not a proof against lost notifications or a substitute for memory ordering. No idle sequence was executed here. The acceptance target is code that tolerates a return without a handler and checks real work again, while preserving the platform’s already-required synchronization and power sequence.

Similar Posts

Leave a Reply

Your email address will not be published. Required fields are marked *