Re: [PATCH] RISC-V: KVM: Fix sign extension for MMIO loads

Anup Patel <[email protected]>
Newsgroups org.infradead.lists.kvm-riscv,org.infradead.lists.linux-riscv,org.kernel.vger.kvm,org.kernel.vger.linux-kernel
Message-ID <CAAhSdy2z_2OUyzA_MK+V6z_5ucwKN6A6f4j6hNaVH7c904SBQw@mail.gmail.com>
On Thu, May 14, 2026 at 1:47 PM Jiakai Xu <[email protected]> wrote:
>
> The kvm_riscv_vcpu_mmio_return() function handles MMIO read results
> by writing the data back to the guest register. For signed load
> instructions (LB, LH, LW on RV64), the value needs sign-extension
> from a smaller integer to unsigned long.
>
> The current code uses:
>     (ulong)data << shift >> shift
> but (ulong) makes the right shift a logical shift (zero-extend)
> rather than an arithmetic shift (sign-extend), causing incorrect
> results when the MMIO device returns a negative value. For example,
> LB reading 0x80 would return 128 instead of -128.
>
> Fix this by casting to (long) after the left shift so that the
> subsequent right shift is arithmetic and correctly propagates
> the sign bit:
>     (long)((ulong)data << shift) >> shift
>
> Additionally, remove the unnecessary shift assignment for LBU
> (unsigned byte load) since it does not need sign extension.
> This makes LBU consistent with LHU and LWU which already keep
> shift = 0.
>
> Fixes: b91f0e4cb8a3 ("RISC-V: KVM: Factor-out instruction emulation into separate sources")
> Signed-off-by: Jiakai Xu <[email protected]>
> Signed-off-by: Jiakai Xu <[email protected]>
> Assisted-by: OpenClaw:DeepSeek-V3.2

LGTM.

Reviewed-by: Anup Patel <[email protected]>

Queued this patch as fix for Linux-7.1-rcX

Thanks,
Anup

> ---
>  arch/riscv/kvm/vcpu_insn.c | 9 ++++-----
>  1 file changed, 4 insertions(+), 5 deletions(-)
>
> diff --git a/arch/riscv/kvm/vcpu_insn.c b/arch/riscv/kvm/vcpu_insn.c
> index 4d89b94128aea..f09f9251d1f0a 100644
> --- a/arch/riscv/kvm/vcpu_insn.c
> +++ b/arch/riscv/kvm/vcpu_insn.c
> @@ -415,7 +415,6 @@ int kvm_riscv_vcpu_mmio_load(struct kvm_vcpu *vcpu, struct kvm_run *run,
>                 shift = 8 * (sizeof(ulong) - len);
>         } else if ((insn & INSN_MASK_LBU) == INSN_MATCH_LBU) {
>                 len = 1;
> -               shift = 8 * (sizeof(ulong) - len);
>  #ifdef CONFIG_64BIT
>         } else if ((insn & INSN_MASK_LD) == INSN_MATCH_LD) {
>                 len = 8;
> @@ -649,22 +648,22 @@ int kvm_riscv_vcpu_mmio_return(struct kvm_vcpu *vcpu, struct kvm_run *run)
>         case 1:
>                 data8 = *((u8 *)run->mmio.data);
>                 SET_RD(insn, &vcpu->arch.guest_context,
> -                       (ulong)data8 << shift >> shift);
> +                       (long)((ulong)data8 << shift) >> shift);
>                 break;
>         case 2:
>                 data16 = *((u16 *)run->mmio.data);
>                 SET_RD(insn, &vcpu->arch.guest_context,
> -                       (ulong)data16 << shift >> shift);
> +                       (long)((ulong)data16 << shift) >> shift);
>                 break;
>         case 4:
>                 data32 = *((u32 *)run->mmio.data);
>                 SET_RD(insn, &vcpu->arch.guest_context,
> -                       (ulong)data32 << shift >> shift);
> +                       (long)((ulong)data32 << shift) >> shift);
>                 break;
>         case 8:
>                 data64 = *((u64 *)run->mmio.data);
>                 SET_RD(insn, &vcpu->arch.guest_context,
> -                       (ulong)data64 << shift >> shift);
> +                       (long)((ulong)data64 << shift) >> shift);
>                 break;
>         default:
>                 return -EOPNOTSUPP;
> --
> 2.34.1
>

-- 
kvm-riscv mailing list
[email protected]
http://lists.infradead.org/mailman/listinfo/kvm-riscv
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.