git: 6d7960628f82 - main - arm64 pmap: demote L3C pages in pmap_clear_modify()

From: Alan Cox <alc_at_FreeBSD.org>
Date: Sun, 01 Nov 2026 21:00:00 UTC
The branch main has been updated by alc:

URL: https://cgit.FreeBSD.org/src/commit/?id=6d7960628f825f1eec0959d6000a79ca8a4ae927

commit 6d7960628f825f1eec0959d6000a79ca8a4ae927
Author:     Alan Cox <alc@FreeBSD.org>
AuthorDate: 2026-11-01 18:25:05 +0000
Commit:     Alan Cox <alc@FreeBSD.org>
CommitDate: 2026-11-01 20:56:44 +0000

    arm64 pmap: demote L3C pages in pmap_clear_modify()
    
    When pmap_clear_modify() demotes a dirty L2 block mapping, it write
    protects the L3 entry that maps "m", so that a subsequent write access
    may repromote.  However, since fd6cb031f577, the L3 entries created by
    pmap_demote_l2_locked() may have ATTR_CONTIGUOUS set, and
    pmap_clear_modify() was write protecting one L3 entry within an L3C page
    while leaving the page's other L3 entries writeable with ATTR_CONTIGUOUS
    still set.  A TLB entry that a processor creates from any of those other
    L3 entries may translate "m"'s virtual address and permit writes to "m"
    without a fault.  To fix this issue, as in pmap_remove_write(), demote
    the L3C page before write protecting the L3 entry.
    
    Found by:       Claude Code (Opus 5.5)
    Fixes:  fd6cb031f577 "arm64 pmap: Add ATTR_CONTIGUOUS support [Part 1]"
    MFC after:      1 week
---
 sys/arm64/arm64/pmap.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/sys/arm64/arm64/pmap.c b/sys/arm64/arm64/pmap.c
index f27ddd379976..6ed49f051ac5 100644
--- a/sys/arm64/arm64/pmap.c
+++ b/sys/arm64/arm64/pmap.c
@@ -8369,6 +8369,8 @@ restart:
 			 */
 			va += VM_PAGE_TO_PHYS(m) - PTE_TO_PHYS(oldl2);
 			l3 = pmap_l2_to_l3(l2, va);
+			if ((pmap_load(l3) & ATTR_CONTIGUOUS) != 0)
+				(void)pmap_demote_l3c(pmap, l3, va);
 			oldl3 = pmap_load(l3);
 			while (!atomic_fcmpset_long(l3, &oldl3,
 			    (oldl3 & ~ATTR_SW_DBM) | ATTR_S1_AP(ATTR_S1_AP_RO)))