[PATCH v2] RISC-V: KVM: Fix the conversion between vsip and hvip
Anup Patel
anup at brainfault.org
Thu Sep 10 02:15:27 PDT 2026
On Tue, Aug 4, 2026 at 7:10 PM Yicong Yang <yang.yicong at picoheart.com> wrote:
>
> Per AIA spec 1.0 Section 6.3.2, the interrupt numbers 13-63
> shares same bit position between related VS shadow CSRs and
> hypervisor CSRs. So there's a shift only for SSI, STI and
> SEI interrupt.
>
> Currently the KVM always does a shift for all the interrupts
> (include LCOFI with number 13) when doing the conversion
> between vsip and hvip. Fix this by only doing shift the SSI,
> STI and SEI. Add wrappers for doing the conversion between
> vsip and hvip.
>
> Fixes: 16b0bde9a37c ("RISC-V: KVM: Add perf sampling support for guests")
> Signed-off-by: Yicong Yang <yang.yicong at picoheart.com>
LGTM.
Reviewed-by: Anup Patel <anup at brainfault.org>
Queued this as fix for Linux-7.3-rcX
Thanks,
Anup
> ---
> Change since v1:
> - rebase on -rc6 and fixed the conflict
> - add fix tag since it fixes the LCOFI injection
> Link: https://lore.kernel.org/linux-riscv/20260721141815.80677-1-yang.yicong@picoheart.com/
>
> arch/riscv/include/asm/csr.h | 20 ++++++++++++++++----
> arch/riscv/kvm/vcpu.c | 3 +--
> arch/riscv/kvm/vcpu_onereg.c | 8 +++-----
> tools/arch/riscv/include/asm/csr.h | 20 ++++++++++++++++----
> 4 files changed, 36 insertions(+), 15 deletions(-)
>
> diff --git a/arch/riscv/include/asm/csr.h b/arch/riscv/include/asm/csr.h
> index d806a979f595..7bfbda958f0f 100644
> --- a/arch/riscv/include/asm/csr.h
> +++ b/arch/riscv/include/asm/csr.h
> @@ -184,12 +184,24 @@
> #define HGATP_MODE_SHIFT HGATP32_MODE_SHIFT
> #endif
>
> -/* VSIP & HVIP relation */
> +/*
> + * VSIP & HVIP relation
> + *
> + * The bit positions are same between VSIP and HVIP for interrupt
> + * numbers 13-63, where there's a shift for the SSI, STI and SEI.
> + */
> #define VSIP_TO_HVIP_SHIFT (IRQ_VS_SOFT - IRQ_S_SOFT)
> -#define VSIP_VALID_MASK ((_AC(1, UL) << IRQ_S_SOFT) | \
> +#define VSIP_BIAS_MASK ((_AC(1, UL) << IRQ_S_SOFT) | \
> (_AC(1, UL) << IRQ_S_TIMER) | \
> - (_AC(1, UL) << IRQ_S_EXT) | \
> - (_AC(1, UL) << IRQ_PMU_OVF))
> + (_AC(1, UL) << IRQ_S_EXT))
> +#define VSIP_NO_BIAS_MASK (_AC(1, UL) << IRQ_PMU_OVF)
> +#define VSIP_VALID_MASK (VSIP_BIAS_MASK | VSIP_NO_BIAS_MASK)
> +#define vsip_to_hvip(_vsip) ((((_vsip) & VSIP_BIAS_MASK) << \
> + VSIP_TO_HVIP_SHIFT) | \
> + ((_vsip) & VSIP_NO_BIAS_MASK))
> +#define hvip_to_vsip(_hvip) ((((_hvip) >> VSIP_TO_HVIP_SHIFT) & \
> + VSIP_BIAS_MASK) | \
> + ((_hvip) & VSIP_NO_BIAS_MASK))
>
> /* AIA CSR bits */
> #define TOPI_IID_SHIFT 16
> diff --git a/arch/riscv/kvm/vcpu.c b/arch/riscv/kvm/vcpu.c
> index 977e36ab83d3..468918309dff 100644
> --- a/arch/riscv/kvm/vcpu.c
> +++ b/arch/riscv/kvm/vcpu.c
> @@ -475,8 +475,7 @@ bool kvm_riscv_vcpu_has_interrupts(struct kvm_vcpu *vcpu, u64 mask)
> bool ret;
>
> raw_spin_lock_irqsave(&vcpu->arch.irqs_pending_lock, flags);
> - ie = ((vcpu->arch.guest_csr.vsie & VSIP_VALID_MASK)
> - << VSIP_TO_HVIP_SHIFT) & (unsigned long)mask;
> + ie = vsip_to_hvip(vcpu->arch.guest_csr.vsie) & (unsigned long)mask;
> ie |= vcpu->arch.guest_csr.vsie & ~IRQ_LOCAL_MASK &
> (unsigned long)mask;
> ret = vcpu->arch.irqs_pending[0] & ie;
> diff --git a/arch/riscv/kvm/vcpu_onereg.c b/arch/riscv/kvm/vcpu_onereg.c
> index 99b9107b1ac1..9fe829eed178 100644
> --- a/arch/riscv/kvm/vcpu_onereg.c
> +++ b/arch/riscv/kvm/vcpu_onereg.c
> @@ -272,7 +272,7 @@ static int kvm_riscv_vcpu_general_get_csr(struct kvm_vcpu *vcpu,
>
> if (reg_num == KVM_REG_RISCV_CSR_REG(sip)) {
> kvm_riscv_vcpu_flush_interrupts(vcpu);
> - *out_val = (csr->hvip >> VSIP_TO_HVIP_SHIFT) & VSIP_VALID_MASK;
> + *out_val = hvip_to_vsip(csr->hvip);
> *out_val |= csr->hvip & ~IRQ_LOCAL_MASK;
> } else
> *out_val = ((unsigned long *)csr)[reg_num];
> @@ -293,10 +293,8 @@ static int kvm_riscv_vcpu_general_set_csr(struct kvm_vcpu *vcpu,
>
> reg_num = array_index_nospec(reg_num, regs_max);
>
> - if (reg_num == KVM_REG_RISCV_CSR_REG(sip)) {
> - reg_val &= VSIP_VALID_MASK;
> - reg_val <<= VSIP_TO_HVIP_SHIFT;
> - }
> + if (reg_num == KVM_REG_RISCV_CSR_REG(sip))
> + reg_val = vsip_to_hvip(reg_val);
>
> ((unsigned long *)csr)[reg_num] = reg_val;
>
> diff --git a/tools/arch/riscv/include/asm/csr.h b/tools/arch/riscv/include/asm/csr.h
> index 21d8cee04638..8df64314d613 100644
> --- a/tools/arch/riscv/include/asm/csr.h
> +++ b/tools/arch/riscv/include/asm/csr.h
> @@ -163,12 +163,24 @@
> #define HGATP_MODE_SHIFT HGATP32_MODE_SHIFT
> #endif
>
> -/* VSIP & HVIP relation */
> +/*
> + * VSIP & HVIP relation
> + *
> + * The bit positions are same between VSIP and HVIP for interrupt
> + * numbers 13-63, where there's a shift for the SSI, STI and SEI.
> + */
> #define VSIP_TO_HVIP_SHIFT (IRQ_VS_SOFT - IRQ_S_SOFT)
> -#define VSIP_VALID_MASK ((_AC(1, UL) << IRQ_S_SOFT) | \
> +#define VSIP_BIAS_MASK ((_AC(1, UL) << IRQ_S_SOFT) | \
> (_AC(1, UL) << IRQ_S_TIMER) | \
> - (_AC(1, UL) << IRQ_S_EXT) | \
> - (_AC(1, UL) << IRQ_PMU_OVF))
> + (_AC(1, UL) << IRQ_S_EXT))
> +#define VSIP_NO_BIAS_MASK (_AC(1, UL) << IRQ_PMU_OVF)
> +#define VSIP_VALID_MASK (VSIP_BIAS_MASK | VSIP_NO_BIAS_MASK)
> +#define vsip_to_hvip(_vsip) ((((_vsip) & VSIP_BIAS_MASK) << \
> + VSIP_TO_HVIP_SHIFT) | \
> + ((_vsip) & VSIP_NO_BIAS_MASK))
> +#define hvip_to_vsip(_hvip) ((((_hvip) >> VSIP_TO_HVIP_SHIFT) & \
> + VSIP_BIAS_MASK) | \
> + ((_hvip) & VSIP_NO_BIAS_MASK))
>
> /* AIA CSR bits */
> #define TOPI_IID_SHIFT 16
> --
> 2.50.1 (Apple Git-155)
More information about the linux-riscv
mailing list