git: 580958427536 - main - arm64: Handle changing self-referential DMAP pages

From: Andrew Turner <andrew_at_FreeBSD.org>
Date: Mon, 13 Apr 2026 14:24:05 UTC
The branch main has been updated by andrew:

URL: https://cgit.FreeBSD.org/src/commit/?id=5809584275363d6b2f44981d8561a126a1344360

commit 5809584275363d6b2f44981d8561a126a1344360
Author:     Andrew Turner <andrew@FreeBSD.org>
AuthorDate: 2026-04-13 11:50:47 +0000
Commit:     Andrew Turner <andrew@FreeBSD.org>
CommitDate: 2026-04-13 14:23:05 +0000

    arm64: Handle changing self-referential DMAP pages
    
    Support changing the property of a DMAP page that holds it's own page
    table entry.
    
    Because we need to perform a break-before-make sequence to change the
    properties of pages a page that also holds it's own page table entry
    will fault in the make part of the sequence.
    
    Handle this by mapping the page with a temporary mapping as we already
    do when demoting a superpage.
    
    Reviewed by:    kib
    Sponsored by:   Arm Ltd
    Differential Revision:  https://reviews.freebsd.org/D55943
---
 sys/arm64/arm64/pmap.c | 26 ++++++++++++++++++++++++++
 1 file changed, 26 insertions(+)

diff --git a/sys/arm64/arm64/pmap.c b/sys/arm64/arm64/pmap.c
index 7d19c927d369..a23905994846 100644
--- a/sys/arm64/arm64/pmap.c
+++ b/sys/arm64/arm64/pmap.c
@@ -8248,6 +8248,7 @@ pmap_change_props_locked(vm_offset_t va, vm_size_t size, vm_prot_t prot,
 	vm_paddr_t pa;
 	pt_entry_t pte, *ptep, *newpte;
 	pt_entry_t bits, mask;
+	char *tmpptep;
 	int lvl, rv;
 
 	PMAP_LOCK_ASSERT(kernel_pmap, MA_OWNED);
@@ -8377,6 +8378,24 @@ pmap_change_props_locked(vm_offset_t va, vm_size_t size, vm_prot_t prot,
 				break;
 			}
 
+			tmpptep = 0;
+			if (tmpva <= (vm_offset_t)ptep &&
+			    tmpva + pte_size > (vm_offset_t)ptep) {
+				vm_paddr_t pte_pa;
+
+				mtx_lock(&cmap_lock);
+				tmpptep = cmap1_addr;
+				pte_pa = DMAP_TO_PHYS((vm_offset_t)ptep);
+				pmap_store(cmap1_pte, ATTR_AF |
+				    pmap_sh_attr | ATTR_S1_AP(ATTR_S1_AP_RW) |
+				    ATTR_S1_XN | ATTR_KERN_GP |
+				    ATTR_S1_IDX(VM_MEMATTR_WRITE_BACK) |
+				    PHYS_TO_PTE(pte_pa &~L3_OFFSET) | L3_PAGE);
+				dsb(ishst);
+				ptep = (pt_entry_t *)(tmpptep +
+				    ((vm_offset_t)ptep & PAGE_MASK));
+			}
+
 			/* Update the entry */
 			pte = pmap_load(ptep);
 			pte &= ~mask;
@@ -8403,6 +8422,13 @@ pmap_change_props_locked(vm_offset_t va, vm_size_t size, vm_prot_t prot,
 				break;
 			}
 
+			if (tmpptep != 0) {
+				pmap_clear(cmap1_pte);
+				pmap_s1_invalidate_page(kernel_pmap,
+				    (vm_offset_t)tmpptep, true);
+				mtx_unlock(&cmap_lock);
+			}
+
 			pa = PTE_TO_PHYS(pte);
 			if (!VIRT_IN_DMAP(tmpva) && PHYS_IN_DMAP(pa)) {
 				/*