git: 57407179be43 - main - arm64 pmap: correct the condition for flushing the icache

From: Alan Cox <alc_at_FreeBSD.org>
Date: Fri, 04 Sep 2026 05:22:47 UTC
The branch main has been updated by alc:

URL: https://cgit.FreeBSD.org/src/commit/?id=57407179be431dbe567de083aab5ce152163f4d3

commit 57407179be431dbe567de083aab5ce152163f4d3
Author:     Alan Cox <alc@FreeBSD.org>
AuthorDate: 2026-08-29 07:08:01 +0000
Commit:     Alan Cox <alc@FreeBSD.org>
CommitDate: 2026-09-04 05:19:13 +0000

    arm64 pmap: correct the condition for flushing the icache
    
    Whenever we create a user-space mapping, we always set ATTR_S1_PXN in
    the PTE, which blocks execution of user-space code while running in
    kernel mode.  However, when seeking to determine whether we need to
    perform an icache flush before installing the new PTE, we test whether
    sometimes the old PTE or other times the new PTE has ATTR_S1_XN set.
    The trouble is that ATTR_S1_XN is defined as the bitwise OR of
    ATTR_S1_PXN and ATTR_S1_UXN, and so the test for whether ATTR_S1_XN is
    set is satisfied if either of its constituent bits is set, i.e., we
    write (l3e & ATTR_S1_XN) != 0.  Consequently, the test is always true.
    
    In practice, I believe that the ill effects of this bug are limited:
    In pmap_enter(), in rare circumstances, e.g., wiring a code page, an
    unnecessary icache flush will be performed.  In pmap_enter_l2() and
    pmap_enter_l3c(), no icache flush will be performed.  However,
    typically an icache flush would have already been performed on each of
    the constituent base pages.
    
    Reviewed by:    kib, markj
    MFC after:      3 weeks
    Differential Revision:  https://reviews.freebsd.org/D59265
---
 sys/arm64/arm64/pmap.c | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/sys/arm64/arm64/pmap.c b/sys/arm64/arm64/pmap.c
index 8f68be2fb272..a584812df0bb 100644
--- a/sys/arm64/arm64/pmap.c
+++ b/sys/arm64/arm64/pmap.c
@@ -5929,7 +5929,7 @@ validate:
 		*/
 		if ((prot & VM_PROT_EXECUTE) &&  pmap != kernel_pmap &&
 		    m->md.pv_memattr == VM_MEMATTR_WRITE_BACK &&
-		    (opa != pa || (orig_l3 & ATTR_S1_XN))) {
+		    (opa != pa || (orig_l3 & ATTR_S1_UXN) != 0)) {
 			PMAP_ASSERT_STAGE1(pmap);
 			cpu_icache_sync_range(PHYS_TO_DMAP(pa), PAGE_SIZE);
 		}
@@ -6242,8 +6242,8 @@ pmap_enter_l2(pmap_t pmap, vm_offset_t va, pd_entry_t new_l2, u_int flags,
 	/*
 	 * Conditionally sync the icache.  See pmap_enter() for details.
 	 */
-	if ((new_l2 & ATTR_S1_XN) == 0 && (PTE_TO_PHYS(new_l2) !=
-	    PTE_TO_PHYS(old_l2) || (old_l2 & ATTR_S1_XN) != 0) &&
+	if ((new_l2 & ATTR_S1_UXN) == 0 && (PTE_TO_PHYS(new_l2) !=
+	    PTE_TO_PHYS(old_l2) || (old_l2 & ATTR_S1_UXN) != 0) &&
 	    pmap != kernel_pmap && m->md.pv_memattr == VM_MEMATTR_WRITE_BACK) {
 		cpu_icache_sync_range(PHYS_TO_DMAP(PTE_TO_PHYS(new_l2)),
 		    L2_SIZE);
@@ -6470,7 +6470,7 @@ have_l3p:
 	/*
 	 * Sync the icache before the mapping is stored.
 	 */
-	if ((l3e & ATTR_S1_XN) == 0 && pmap != kernel_pmap &&
+	if ((l3e & ATTR_S1_UXN) == 0 && pmap != kernel_pmap &&
 	    m->md.pv_memattr == VM_MEMATTR_WRITE_BACK)
 		cpu_icache_sync_range(PHYS_TO_DMAP(pa), L3C_SIZE);