[PATCH] RISC-V: KVM: Guard HFENCE range loops against overflow

Anup Patel anup at brainfault.org
Sat Aug 8 01:22:24 PDT 2026


On Sat, Jul 18, 2026 at 10:08 AM Pengpeng Hou <pengpeng at iscas.ac.cn> wrote:
>
> The local HFENCE range helpers build the loop end with addr + size and
> then step through the range by the requested page order. If addr + size
> wraps, a small range near the top of the address space can be treated as
> empty and skip the intended fence. The final loop step can also wrap
> before the loop condition is evaluated again.
>
> Treat wrapped ranges conservatively as full-range HFENCE requests and stop
> each bounded loop before the next step can wrap past the computed end. This
> keeps the existing large-range fallback and only changes local GVMA/VVMA
> range construction.
>
> Fixes: 2415e46e3a9a ("RISC-V: KVM: Introduce range based local HFENCE functions")
> Signed-off-by: Pengpeng Hou <pengpeng at iscas.ac.cn>

LGTM.

Reviewed-by: Anup Patel <anup at brainfault.org>

Queued this patch for Linux-7.3

Thanks,
Anup


> ---
>  arch/riscv/kvm/tlb.c | 71 ++++++++++++++++++++++++++++++++++++--------
>  1 file changed, 59 insertions(+), 12 deletions(-)
>
> diff --git a/arch/riscv/kvm/tlb.c b/arch/riscv/kvm/tlb.c
> index 993b25ea94d67..b0c83e3ccc15a 100644
> --- a/arch/riscv/kvm/tlb.c
> +++ b/arch/riscv/kvm/tlb.c
> @@ -8,6 +8,7 @@
>  #include <linux/errno.h>
>  #include <linux/err.h>
>  #include <linux/module.h>
> +#include <linux/overflow.h>
>  #include <linux/smp.h>
>  #include <linux/kvm_host.h>
>  #include <asm/cacheflush.h>
> @@ -24,7 +25,12 @@ void kvm_riscv_local_hfence_gvma_vmid_gpa(unsigned long vmid,
>                                           gpa_t gpa, gpa_t gpsz,
>                                           unsigned long order)
>  {
> -       gpa_t pos;
> +       gpa_t end, pos, step = BIT(order);
> +
> +       if (check_add_overflow(gpa, gpsz, &end)) {
> +               kvm_riscv_local_hfence_gvma_vmid_all(vmid);
> +               return;
> +       }
>
>         if (PTRS_PER_PTE < (gpsz >> order)) {
>                 kvm_riscv_local_hfence_gvma_vmid_all(vmid);
> @@ -33,14 +39,20 @@ void kvm_riscv_local_hfence_gvma_vmid_gpa(unsigned long vmid,
>
>         if (has_svinval()) {
>                 asm volatile (SFENCE_W_INVAL() ::: "memory");
> -               for (pos = gpa; pos < (gpa + gpsz); pos += BIT(order))
> +               for (pos = gpa; pos < end; pos += step) {
>                         asm volatile (HINVAL_GVMA(%0, %1)
>                         : : "r" (pos >> 2), "r" (vmid) : "memory");
> +                       if (end - pos <= step)
> +                               break;
> +               }
>                 asm volatile (SFENCE_INVAL_IR() ::: "memory");
>         } else {
> -               for (pos = gpa; pos < (gpa + gpsz); pos += BIT(order))
> +               for (pos = gpa; pos < end; pos += step) {
>                         asm volatile (HFENCE_GVMA(%0, %1)
>                         : : "r" (pos >> 2), "r" (vmid) : "memory");
> +                       if (end - pos <= step)
> +                               break;
> +               }
>         }
>  }
>
> @@ -52,7 +64,12 @@ void kvm_riscv_local_hfence_gvma_vmid_all(unsigned long vmid)
>  void kvm_riscv_local_hfence_gvma_gpa(gpa_t gpa, gpa_t gpsz,
>                                      unsigned long order)
>  {
> -       gpa_t pos;
> +       gpa_t end, pos, step = BIT(order);
> +
> +       if (check_add_overflow(gpa, gpsz, &end)) {
> +               kvm_riscv_local_hfence_gvma_all();
> +               return;
> +       }
>
>         if (PTRS_PER_PTE < (gpsz >> order)) {
>                 kvm_riscv_local_hfence_gvma_all();
> @@ -61,14 +78,20 @@ void kvm_riscv_local_hfence_gvma_gpa(gpa_t gpa, gpa_t gpsz,
>
>         if (has_svinval()) {
>                 asm volatile (SFENCE_W_INVAL() ::: "memory");
> -               for (pos = gpa; pos < (gpa + gpsz); pos += BIT(order))
> +               for (pos = gpa; pos < end; pos += step) {
>                         asm volatile(HINVAL_GVMA(%0, zero)
>                         : : "r" (pos >> 2) : "memory");
> +                       if (end - pos <= step)
> +                               break;
> +               }
>                 asm volatile (SFENCE_INVAL_IR() ::: "memory");
>         } else {
> -               for (pos = gpa; pos < (gpa + gpsz); pos += BIT(order))
> +               for (pos = gpa; pos < end; pos += step) {
>                         asm volatile(HFENCE_GVMA(%0, zero)
>                         : : "r" (pos >> 2) : "memory");
> +                       if (end - pos <= step)
> +                               break;
> +               }
>         }
>  }
>
> @@ -83,7 +106,13 @@ void kvm_riscv_local_hfence_vvma_asid_gva(unsigned long vmid,
>                                           unsigned long gvsz,
>                                           unsigned long order)
>  {
> -       unsigned long pos, hgatp;
> +       unsigned long end, pos, step = BIT(order);
> +       unsigned long hgatp;
> +
> +       if (check_add_overflow(gva, gvsz, &end)) {
> +               kvm_riscv_local_hfence_vvma_asid_all(vmid, asid);
> +               return;
> +       }
>
>         if (PTRS_PER_PTE < (gvsz >> order)) {
>                 kvm_riscv_local_hfence_vvma_asid_all(vmid, asid);
> @@ -94,14 +123,20 @@ void kvm_riscv_local_hfence_vvma_asid_gva(unsigned long vmid,
>
>         if (has_svinval()) {
>                 asm volatile (SFENCE_W_INVAL() ::: "memory");
> -               for (pos = gva; pos < (gva + gvsz); pos += BIT(order))
> +               for (pos = gva; pos < end; pos += step) {
>                         asm volatile(HINVAL_VVMA(%0, %1)
>                         : : "r" (pos), "r" (asid) : "memory");
> +                       if (end - pos <= step)
> +                               break;
> +               }
>                 asm volatile (SFENCE_INVAL_IR() ::: "memory");
>         } else {
> -               for (pos = gva; pos < (gva + gvsz); pos += BIT(order))
> +               for (pos = gva; pos < end; pos += step) {
>                         asm volatile(HFENCE_VVMA(%0, %1)
>                         : : "r" (pos), "r" (asid) : "memory");
> +                       if (end - pos <= step)
> +                               break;
> +               }
>         }
>
>         csr_write(CSR_HGATP, hgatp);
> @@ -123,7 +158,13 @@ void kvm_riscv_local_hfence_vvma_gva(unsigned long vmid,
>                                      unsigned long gva, unsigned long gvsz,
>                                      unsigned long order)
>  {
> -       unsigned long pos, hgatp;
> +       unsigned long end, pos, step = BIT(order);
> +       unsigned long hgatp;
> +
> +       if (check_add_overflow(gva, gvsz, &end)) {
> +               kvm_riscv_local_hfence_vvma_all(vmid);
> +               return;
> +       }
>
>         if (PTRS_PER_PTE < (gvsz >> order)) {
>                 kvm_riscv_local_hfence_vvma_all(vmid);
> @@ -134,14 +175,20 @@ void kvm_riscv_local_hfence_vvma_gva(unsigned long vmid,
>
>         if (has_svinval()) {
>                 asm volatile (SFENCE_W_INVAL() ::: "memory");
> -               for (pos = gva; pos < (gva + gvsz); pos += BIT(order))
> +               for (pos = gva; pos < end; pos += step) {
>                         asm volatile(HINVAL_VVMA(%0, zero)
>                         : : "r" (pos) : "memory");
> +                       if (end - pos <= step)
> +                               break;
> +               }
>                 asm volatile (SFENCE_INVAL_IR() ::: "memory");
>         } else {
> -               for (pos = gva; pos < (gva + gvsz); pos += BIT(order))
> +               for (pos = gva; pos < end; pos += step) {
>                         asm volatile(HFENCE_VVMA(%0, zero)
>                         : : "r" (pos) : "memory");
> +                       if (end - pos <= step)
> +                               break;
> +               }
>         }
>
>         csr_write(CSR_HGATP, hgatp);
> --
> 2.43.0
>



More information about the kvm-riscv mailing list