git: 7dd9a8125f70 - main - arm64: a local TLB invalidation suffices when enabling write access

From: Alan Cox <alc_at_FreeBSD.org>
Date: Wed, 07 Oct 2026 14:24:14 UTC
The branch main has been updated by alc:

URL: https://cgit.FreeBSD.org/src/commit/?id=7dd9a8125f70f1fc40fd9907bdaae0d23c8586c9

commit 7dd9a8125f70f1fc40fd9907bdaae0d23c8586c9
Author:     Alan Cox <alc@FreeBSD.org>
AuthorDate: 2026-10-06 04:53:00 +0000
Commit:     Alan Cox <alc@FreeBSD.org>
CommitDate: 2026-10-07 14:22:57 +0000

    arm64: a local TLB invalidation suffices when enabling write access
    
    When a PTE logically supports write access, as indicated by its DBM
    field, but write access is nonetheless blocked by the PTE's protection
    field, pmap_fault() can enable write access with only a local TLB
    invalidation.
    
    Reviewed by:    andrew, kib, markj
    MFC after:      1 week
    Differential Revision:  https://reviews.freebsd.org/D60417
---
 sys/arm64/arm64/pmap.c | 36 +++++++++++++++++++++++++++++++++---
 1 file changed, 33 insertions(+), 3 deletions(-)

diff --git a/sys/arm64/arm64/pmap.c b/sys/arm64/arm64/pmap.c
index acdcfe7fea8c..97cbb92d6d43 100644
--- a/sys/arm64/arm64/pmap.c
+++ b/sys/arm64/arm64/pmap.c
@@ -2152,6 +2152,31 @@ pmap_s1_invalidate_page(pmap_t pmap, vm_offset_t va, bool final_only)
 	isb();
 }
 
+/*
+ * Invalidates any cached final-level TLB entry for the specified virtual
+ * address in the given virtual address space, but only on the current
+ * processor.
+ *
+ * The pmap_multiple_tlbi errata only affect broadcast invalidations.
+ */
+static __inline void
+pmap_s1_invalidate_page_local(pmap_t pmap, vm_offset_t va)
+{
+	uint64_t r;
+
+	PMAP_ASSERT_STAGE1(pmap);
+	dsb(nshst);
+	r = TLBI_VA(va);
+	if (pmap == kernel_pmap) {
+		__asm __volatile("tlbi vaale1, %0" : : "r" (r));
+	} else {
+		r |= ASID_TO_OPERAND(COOKIE_TO_ASID(pmap->pm_cookie));
+		__asm __volatile("tlbi vale1, %0" : : "r" (r));
+	}
+	dsb(nsh);
+	isb();
+}
+
 static __inline void
 pmap_s2_invalidate_page(pmap_t pmap, vm_offset_t va, bool final_only)
 {
@@ -9965,11 +9990,16 @@ pmap_fault(pmap_t pmap, uint64_t esr, uint64_t far)
 		ptep = pmap_pte(pmap, far, &lvl);
 		if (ptep != NULL &&
 		    ((pte = pmap_load(ptep)) & ATTR_SW_DBM) != 0) {
+			/*
+			 * A local invalidation suffices when enabling write
+			 * access.  At worst, a write using a stale read-only
+			 * TLB entry on another processor triggers a fault,
+			 * requiring its own local invalidation below.
+			 */
 			if ((pte & ATTR_S1_AP_RW_BIT) ==
-			    ATTR_S1_AP(ATTR_S1_AP_RO)) {
+			    ATTR_S1_AP(ATTR_S1_AP_RO))
 				pmap_clear_bits(ptep, ATTR_S1_AP_RW_BIT);
-				pmap_s1_invalidate_page(pmap, far, true);
-			}
+			pmap_s1_invalidate_page_local(pmap, far);
 			rv = KERN_SUCCESS;
 		}
 		PMAP_UNLOCK(pmap);