[<prev] [next>] [<thread-prev] [day] [month] [year] [list]
Message-ID: <CAK9=C2XjygELuUnQErbpVzh6-4wc4HHypf91aKUtUzMYGJwmtw@mail.gmail.com>
Date: Fri, 24 Oct 2025 09:22:12 +0530
From: Anup Patel <apatel@...tanamicro.com>
To: Hui Min Mina Chou <minachou@...estech.com>
Cc: anup@...infault.org, atish.patra@...ux.dev, pjw@...nel.org,
palmer@...belt.com, aou@...s.berkeley.edu, alex@...ti.fr, kvm@...r.kernel.org,
kvm-riscv@...ts.infradead.org, linux-riscv@...ts.infradead.org,
linux-kernel@...r.kernel.org, tim609@...estech.com, ben717@...estech.com,
az70021@...il.com
Subject: Re: [PATCH v2] RISC-V: KVM: flush VS-stage TLB after VCPU migration
to prevent stale entries
On Tue, Oct 21, 2025 at 2:02 PM Hui Min Mina Chou
<minachou@...estech.com> wrote:
>
> From: Hui Min Mina Chou <minachou@...estech.com>
>
> If multiple VCPUs of the same Guest/VM run on the same Host CPU,
> hfence.vvma only flushes that Host CPU’s VS-stage TLB. Other Host CPUs
> may retain stale VS-stage entries. When a VCPU later migrates to a
> different Host CPU, it can hit these stale GVA to GPA mappings, causing
> unexpected faults in the Guest.
>
> To fix this, kvm_riscv_gstage_vmid_sanitize() is extended to flush both
> G-stage and VS-stage TLBs whenever a VCPU migrates to a different Host CPU.
> This ensures that no stale VS-stage mappings remain after VCPU migration.
>
> Fixes: 92e450507d56 ("RISC-V: KVM: Cleanup stale TLB entries when host CPU changes")
> Signed-off-by: Hui Min Mina Chou <minachou@...estech.com>
> Signed-off-by: Ben Zong-You Xie <ben717@...estech.com>
Here's what the non-normative text says about HFENCE.GVMA ...
"Conceptually, an implementation might contain two address-translation
caches: one that
maps guest virtual addresses to guest physical addresses, and another
that maps guest
physical addresses to supervisor physical addresses. HFENCE.GVMA need
not flush the
former cache, but it must flush entries from the latter cache that
match the HFENCE.GVMA’s
address and VMID arguments."
"More commonly, implementations contain address-translation caches
that map guest virtual
addresses directly to supervisor physical addresses, removing a level
of indirection. For such
implementations, any entry whose guest virtual address maps to a guest
physical address that
matches the HFENCE.GVMA’s address and VMID arguments must be flushed.
Selectively
flushing entries in this fashion requires tagging them with the guest
physical address, which is
costly, and so a common technique is to flush all entries that match
the HFENCE.GVMA’s
VMID argument, regardless of the address argument."
This means ...
For implementations (most common) which have TLBs caching
guest virtual address to supervisor physical address, the
kvm_riscv_local_hfence_gvma_vmid_all() is sufficient upon
VCPU migrating to a different host CPU.
For implementations (relatively uncommon) which have TLBs
caching guest virtual address to guest physical address, the
HFENCE.GVMA will not touch guest virtual address to guest
physical address mapping and KVM must explicitly sanitize
VS-stage mappings using HFENCE.VVMA (like this patch)
when migrating VCPU to a different host CPU.
We should not penalize all implementations by explicitly calling
kvm_riscv_local_hfence_vvma_all() rather this should be only
done on implementations where it is required using a static jump.
One possible way of detecting whether the underlying implementation
needs explicit HFENCE.VVMA upon VCPU is to use marchid,
mimpid, and mvendorid. Another way is to use implementation
specific CPU compatible strings.
Regards,
Anup
> ---
> Changes in v2:
> - Updated Fixes commit to 92e450507d56
> - Renamed function to kvm_riscv_local_tlb_sanitize
>
> arch/riscv/kvm/vmid.c | 8 +++++++-
> 1 file changed, 7 insertions(+), 1 deletion(-)
>
> diff --git a/arch/riscv/kvm/vmid.c b/arch/riscv/kvm/vmid.c
> index 3b426c800480..6323f5383d36 100644
> --- a/arch/riscv/kvm/vmid.c
> +++ b/arch/riscv/kvm/vmid.c
> @@ -125,7 +125,7 @@ void kvm_riscv_gstage_vmid_update(struct kvm_vcpu *vcpu)
> kvm_make_request(KVM_REQ_UPDATE_HGATP, v);
> }
>
> -void kvm_riscv_gstage_vmid_sanitize(struct kvm_vcpu *vcpu)
> +void kvm_riscv_local_tlb_sanitize(struct kvm_vcpu *vcpu)
> {
> unsigned long vmid;
>
> @@ -146,4 +146,10 @@ void kvm_riscv_gstage_vmid_sanitize(struct kvm_vcpu *vcpu)
>
> vmid = READ_ONCE(vcpu->kvm->arch.vmid.vmid);
> kvm_riscv_local_hfence_gvma_vmid_all(vmid);
> +
> + /*
> + * Flush VS-stage TLBs entry after VCPU migration to avoid using
> + * stale entries.
> + */
> + kvm_riscv_local_hfence_vvma_all(vmid);
> }
> --
> 2.34.1
>
>
Powered by blists - more mailing lists