On 16/02/2026 10:39 pm, Andrew Cooper wrote:
>On 16/02/2026 4:10 pm, Abdelkareem Abdelsaamad wrote:
>> On 16/02/2026 10:15 am, Andrew Cooper wrote:
>>> So what happens to the NMI we're trying to inject when NMIs are
>>> currently blocked?
>> Ah, I see this...
>> The handling flow will eventually land on the function svm_enable_intr_window
>> with HVM_INTR_SHADOW_NMI.
>What happens is that you drop the NMI on the floor and discard it. Note
>how svm_inject_nmi() has no return value, and therefore must not fail.
>It is buggy to check the blocked bit when injecting using this
>mechanism. The blocked bit roughly equates to "NMI in progress" in the
>guest, and it is explicitly possible to queue another NMI while the
>first is in progress.
>Both pending and masked being set roughly means "One NMI in progress,
>and one queued", which is a perfectly fine state to be in.
Right, Actually, I see the changes in the svm_get_interrupt_shadow and the
svm_enable_intr_window functions are not correct. There should not be changes
in the two functions. The vNMI handling for multiple\concurrent NMIs should
first set the vnmi_pending bit for the first NMI. The subsequent NMI should
either see the vnmi_pending bit is still set, in which case, it should be just
dropped, i.e, do nothing or it can see the vnmi_pending is cleared in which
case the current vNMI might be is in progress or might be completed but the
code should safely not consider the NMI as blocked, if the vnmi_blocking is
set.
The confusion, I had, is due to looking at the KVM codebase. The upstream
commit fa4c027a7956 ("KVM: x86: Add support for SVM's Virtual NMI") [1]
that was later fixed with the fixing upstream commit
b2ce89978889 ("KVM: SVM: vNMI pending bit is V_NMI_PENDING_MASK not
V_NMI_BLOCKING_MASK")
[2].
--Abdelkareem
[1]https://lore.kernel.org/r/[email protected]
[2]https://lore.kernel.org/r/be4ca192eb0c1e69a210db3009ca984e6a54ae69.1684495380.git.maciej.szmigi...@oracle.com