git: 57407179be43 - main - arm64 pmap: correct the condition for flushing the icache
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
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);