[PATCH] RISC-V: KVM: Fix IPI delivery for out-of-order vcpu_id
Nutty.Liu
nutty.liu at hotmail.com
Thu Sep 24 03:31:05 PDT 2026
On 9/17/2026 8:20 PM, Xiaofeng Yuan wrote:
> The SBI IPI handler walks vCPUs with kvm_for_each_vcpu(), which
> iterates by vcpu_idx (creation order) rather than vcpu_id order.
> Since vcpu_id can be assigned out of order by userspace, a vCPU whose
> hart_bit falls outside the XLEN-bit hart_mask range may be reached
> before vCPUs the mask actually targets. In that case the handler jumps
> to "done" and stops sending IPIs, leaving valid target vCPUs without
> an interrupt.
>
> Replace the early "goto done" with "continue" so vCPUs outside the
> hart_mask range are skipped without aborting the loop.
>
> Reproduced with a minimal userspace VMM driving KVM inside a QEMU
> (RISC-V virt) guest: three vCPUs are created with ids 100, 0, 1 (in
> creation order) and sbi_send_ipi(hart_mask=bit0, hbase=0) is called
> from vcpu_id 1. Before this change the IPI is dropped and the ecall
> returns SBI_ERR_INVALID_PARAM; with this change the IPI is delivered
> and the ecall returns SBI_SUCCESS.
>
> Fixes: 0611f78f83c9 ("riscv: KVM: Fix SBI IPI error generation")
> Cc: stable at vger.kernel.org
> Suggested-by: Andrew Jones <ajones at ventanamicro.com>
> Signed-off-by: Xiaofeng Yuan <yuanxiaofeng at eswincomputing.com>
> ---
> arch/riscv/kvm/vcpu_sbi_replace.c | 12 ++++++++++--
> 1 file changed, 10 insertions(+), 2 deletions(-)
>
> diff --git a/arch/riscv/kvm/vcpu_sbi_replace.c b/arch/riscv/kvm/vcpu_sbi_replace.c
> index 506a510b6..c2f1f7f26 100644
> --- a/arch/riscv/kvm/vcpu_sbi_replace.c
> +++ b/arch/riscv/kvm/vcpu_sbi_replace.c
> @@ -64,8 +64,17 @@ static int kvm_sbi_ext_ipi_handler(struct kvm_vcpu *vcpu, struct kvm_run *run,
> if (tmp->vcpu_id < hbase)
> continue;
> hart_bit = tmp->vcpu_id - hbase;
> + /*
> + * kvm_for_each_vcpu() walks kvm->vcpus[] by
> + * vcpu_idx, i.e. the creation order, which has
> + * nothing to do with the vcpu_id (hart id) space
> + * that the SBI IPI operates on. vcpu_ids need not
> + * increase along the iteration, so harts outside
> + * the hart_mask window must be skipped instead of
> + * aborting the loop.
> + */
> if (hart_bit >= __riscv_xlen)
> - goto done;
> + continue;
> if (!(hmask & (1UL << hart_bit)))
> continue;
Seems the above two 'if' statements can be combined.
Otherwise,
Reviewed-by: Nutty Liu <nutty.liu at hotmail.com>
Thanks,
Nutty
> }
> @@ -76,7 +85,6 @@ static int kvm_sbi_ext_ipi_handler(struct kvm_vcpu *vcpu, struct kvm_run *run,
> kvm_riscv_vcpu_pmu_incr_fw(tmp, SBI_PMU_FW_IPI_RCVD);
> }
>
> -done:
> if (hbase != -1UL && (hmask ^ sentmask))
> retdata->err_val = SBI_ERR_INVALID_PARAM;
>
More information about the linux-riscv
mailing list