Hi stable folks,
I noticed that these two KVM/arm64 pgtable fixes are missing from 6.6.y so I've done the backports. The second one is also needed in 6.1.y but it needs some tweaks so I'll post a separate backport for that.
Cheers,
Will
Cc: Marc Zyngier maz@kernel.org Cc: Oliver Upton oliver.upton@linux.dev cc: kvmarm@lists.linux.dev
--->8
Will Deacon (2): KVM: arm64: Don't defer TLB invalidation when zapping table entries KVM: arm64: Don't pass a TLBI level hint when zapping table entries
arch/arm64/kvm/hyp/pgtable.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-)
commit f62d4c3eb687d87b616b4279acec7862553bda77 upstream.
Commit 7657ea920c54 ("KVM: arm64: Use TLBI range-based instructions for unmap") introduced deferred TLB invalidation for the stage-2 page-table so that range-based invalidation can be used for the accumulated addresses. This works fine if the structure of the page-tables remains unchanged, but if entire tables are zapped and subsequently freed then we transiently leave the hardware page-table walker with a reference to freed memory thanks to the translation walk caches. For example, stage2_unmap_walker() will free page-table pages:
if (childp) mm_ops->put_page(childp);
and issue the TLB invalidation later in kvm_pgtable_stage2_unmap():
if (stage2_unmap_defer_tlb_flush(pgt)) /* Perform the deferred TLB invalidations */ kvm_tlb_flush_vmid_range(pgt->mmu, addr, size);
For now, take the conservative approach and invalidate the TLB eagerly when we clear a table entry. Note, however, that the existing level hint passed to __kvm_tlb_flush_vmid_ipa() is incorrect and will be fixed in a subsequent patch.
Cc: Raghavendra Rao Ananta rananta@google.com Cc: Shaoqin Huang shahuang@redhat.com Cc: Marc Zyngier maz@kernel.org Cc: Oliver Upton oliver.upton@linux.dev Reviewed-by: Shaoqin Huang shahuang@redhat.com Reviewed-by: Marc Zyngier maz@kernel.org Link: https://lore.kernel.org/r/20240327124853.11206-2-will@kernel.org Signed-off-by: Oliver Upton oliver.upton@linux.dev Cc: stable@vger.kernel.org # 6.6.y only Signed-off-by: Will Deacon will@kernel.org --- arch/arm64/kvm/hyp/pgtable.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/arch/arm64/kvm/hyp/pgtable.c b/arch/arm64/kvm/hyp/pgtable.c index 15aa9bad1c28..6692327fabe7 100644 --- a/arch/arm64/kvm/hyp/pgtable.c +++ b/arch/arm64/kvm/hyp/pgtable.c @@ -861,9 +861,11 @@ static void stage2_unmap_put_pte(const struct kvm_pgtable_visit_ctx *ctx, if (kvm_pte_valid(ctx->old)) { kvm_clear_pte(ctx->ptep);
- if (!stage2_unmap_defer_tlb_flush(pgt)) + if (!stage2_unmap_defer_tlb_flush(pgt) || + kvm_pte_table(ctx->old, ctx->level)) { kvm_call_hyp(__kvm_tlb_flush_vmid_ipa, mmu, ctx->addr, ctx->level); + } }
mm_ops->put_page(ctx->ptep);
commit 36e008323926036650299cfbb2dca704c7aba849 upstream.
The TLBI level hints are for leaf entries only, so take care not to pass them incorrectly after clearing a table entry.
Cc: Gavin Shan gshan@redhat.com Cc: Marc Zyngier maz@kernel.org Cc: Quentin Perret qperret@google.com Fixes: 82bb02445de5 ("KVM: arm64: Implement kvm_pgtable_hyp_unmap() at EL2") Fixes: 6d9d2115c480 ("KVM: arm64: Add support for stage-2 map()/unmap() in generic page-table") Signed-off-by: Will Deacon will@kernel.org Reviewed-by: Shaoqin Huang shahuang@redhat.com Reviewed-by: Marc Zyngier maz@kernel.org Link: https://lore.kernel.org/r/20240327124853.11206-3-will@kernel.org Signed-off-by: Oliver Upton oliver.upton@linux.dev Cc: stable@vger.kernel.org # 6.6.y only [will@: Use '0' instead of TLBI_TTL_UNKNOWN to indicate "no level"] Signed-off-by: Will Deacon will@kernel.org --- arch/arm64/kvm/hyp/pgtable.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-)
diff --git a/arch/arm64/kvm/hyp/pgtable.c b/arch/arm64/kvm/hyp/pgtable.c index 6692327fabe7..ca0bf0b92ca0 100644 --- a/arch/arm64/kvm/hyp/pgtable.c +++ b/arch/arm64/kvm/hyp/pgtable.c @@ -523,7 +523,7 @@ static int hyp_unmap_walker(const struct kvm_pgtable_visit_ctx *ctx,
kvm_clear_pte(ctx->ptep); dsb(ishst); - __tlbi_level(vae2is, __TLBI_VADDR(ctx->addr, 0), ctx->level); + __tlbi_level(vae2is, __TLBI_VADDR(ctx->addr, 0), 0); } else { if (ctx->end - ctx->addr < granule) return -EINVAL; @@ -861,10 +861,12 @@ static void stage2_unmap_put_pte(const struct kvm_pgtable_visit_ctx *ctx, if (kvm_pte_valid(ctx->old)) { kvm_clear_pte(ctx->ptep);
- if (!stage2_unmap_defer_tlb_flush(pgt) || - kvm_pte_table(ctx->old, ctx->level)) { - kvm_call_hyp(__kvm_tlb_flush_vmid_ipa, mmu, - ctx->addr, ctx->level); + if (kvm_pte_table(ctx->old, ctx->level)) { + kvm_call_hyp(__kvm_tlb_flush_vmid_ipa, mmu, ctx->addr, + 0); + } else if (!stage2_unmap_defer_tlb_flush(pgt)) { + kvm_call_hyp(__kvm_tlb_flush_vmid_ipa, mmu, ctx->addr, + ctx->level); } }
On Thu, Aug 15, 2024 at 01:46:24PM +0100, Will Deacon wrote:
Hi stable folks,
I noticed that these two KVM/arm64 pgtable fixes are missing from 6.6.y so I've done the backports. The second one is also needed in 6.1.y but it needs some tweaks so I'll post a separate backport for that.
Now queued up, thanks.
greg k-h
linux-stable-mirror@lists.linaro.org