git: 580958427536 - main - arm64: Handle changing self-referential DMAP pages
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
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)) {
/*