Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 27 May 2026 15:24:09 +0000
From:      Andrew Turner <andrew@FreeBSD.org>
To:        src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org
Subject:   git: a780d21eab97 - main - arm64: Support changing the DMAP memory type
Message-ID:  <6a170c99.27186.58925c24@gitrepo.freebsd.org>

index | next in thread | raw e-mail

The branch main has been updated by andrew:

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

commit a780d21eab9724b0667df84b02074994595d51c7
Author:     Andrew Turner <andrew@FreeBSD.org>
AuthorDate: 2026-05-15 15:16:57 +0000
Commit:     Andrew Turner <andrew@FreeBSD.org>
CommitDate: 2026-05-27 15:22:25 +0000

    arm64: Support changing the DMAP memory type
    
    When MTE is enabled we will use the DMAP to manage tags. To be able to
    read/write them we need to change the memory attribute to
    VM_MEMATTR_TAGGED.
    
    Support changing the DMAP memory type to values known to have
    equivalent cache properties.
    
    Sponsored by:   Arm Ltd
    Differential Revision:  https://reviews.freebsd.org/D55949
---
 sys/arm64/arm64/pmap.c   | 64 ++++++++++++++++++++++++++++++++++++++----------
 sys/arm64/include/pmap.h |  1 +
 2 files changed, 52 insertions(+), 13 deletions(-)

diff --git a/sys/arm64/arm64/pmap.c b/sys/arm64/arm64/pmap.c
index adc583812e5b..fd4232711697 100644
--- a/sys/arm64/arm64/pmap.c
+++ b/sys/arm64/arm64/pmap.c
@@ -358,6 +358,7 @@ struct pv_chunks_list __exclusive_cache_line pv_chunks[PMAP_MEMDOM];
 vm_paddr_t dmap_phys_base;	/* The start of the dmap region */
 vm_paddr_t dmap_phys_max;	/* The limit of the dmap region */
 vm_offset_t dmap_max_addr;	/* The virtual address limit of the dmap */
+static int dmap_attr = VM_MEMATTR_WRITE_BACK;
 
 extern pt_entry_t pagetable_l0_ttbr1[];
 
@@ -483,7 +484,7 @@ static void pmap_abort_ptp(pmap_t pmap, vm_offset_t va, vm_page_t mpte);
 static bool pmap_activate_int(struct thread *td, pmap_t pmap);
 static void pmap_alloc_asid(pmap_t pmap);
 static int pmap_change_props_locked(void *addr, vm_size_t size,
-    vm_prot_t prot, int mode, bool skip_unmapped);
+    vm_prot_t prot, int mode, int old_mode, bool skip_unmapped);
 static bool pmap_copy_l3c(pmap_t pmap, pt_entry_t *l3p, vm_offset_t va,
     pt_entry_t l3e, vm_page_t ml3, struct rwlock **lockp);
 static pt_entry_t *pmap_demote_l1(pmap_t pmap, pt_entry_t *l1, vm_offset_t va);
@@ -8161,7 +8162,7 @@ pmap_unmapbios(void *p, vm_size_t size)
 		/* Ensure the attributes are as expected for the DMAP region */
 		PMAP_LOCK(kernel_pmap);
 		error = pmap_change_props_locked(va, size,
-		    PROT_READ | PROT_WRITE, VM_MEMATTR_DEFAULT, false);
+		    PROT_READ | PROT_WRITE, VM_MEMATTR_DEFAULT, -1, false);
 		PMAP_UNLOCK(kernel_pmap);
 		KASSERT(error == 0, ("%s: Failed to reset DMAP attributes: %d",
 		    __func__, error));
@@ -8267,7 +8268,25 @@ pmap_change_attr(void *va, vm_size_t size, int mode)
 	int error;
 
 	PMAP_LOCK(kernel_pmap);
-	error = pmap_change_props_locked(va, size, PROT_NONE, mode, false);
+	error = pmap_change_props_locked(va, size, PROT_NONE, mode, -1, false);
+	PMAP_UNLOCK(kernel_pmap);
+	return (error);
+}
+
+int
+pmap_change_dmap_attr(int mode)
+{
+	int error;
+
+	KASSERT(mode == VM_MEMATTR_WRITE_BACK ||
+	    mode == VM_MEMATTR_TAGGED,
+	    ("%s: mode %d must be compatible with write-back", __func__, mode));
+
+	PMAP_LOCK(kernel_pmap);
+	error = pmap_change_props_locked((void *)DMAP_MIN_ADDRESS,
+	    dmap_max_addr - DMAP_MIN_ADDRESS, PROT_NONE, mode, dmap_attr, true);
+	if (error == 0)
+		dmap_attr = mode;
 	PMAP_UNLOCK(kernel_pmap);
 	return (error);
 }
@@ -8289,20 +8308,20 @@ pmap_change_prot(void *va, vm_size_t size, vm_prot_t prot)
 		return (EINVAL);
 
 	PMAP_LOCK(kernel_pmap);
-	error = pmap_change_props_locked(va, size, prot, -1, false);
+	error = pmap_change_props_locked(va, size, prot, -1, -1, false);
 	PMAP_UNLOCK(kernel_pmap);
 	return (error);
 }
 
 static int
 pmap_change_props_locked(void *addr, vm_size_t size, vm_prot_t prot,
-    int mode, bool skip_unmapped)
+    int mode, int old_mode, bool skip_unmapped)
 {
 	vm_offset_t base, offset, tmpva, va;
 	vm_size_t pte_size;
 	vm_paddr_t pa;
 	pt_entry_t pte, *ptep, *newpte;
-	pt_entry_t bits, mask;
+	pt_entry_t bits, mask, old_mode_bits, old_mode_mask;
 	char *tmpptep;
 	int lvl, rv;
 
@@ -8316,8 +8335,8 @@ pmap_change_props_locked(void *addr, vm_size_t size, vm_prot_t prot,
 	    !(base >= VM_MIN_KERNEL_ADDRESS && base < VM_MAX_KERNEL_ADDRESS))
 		return (EINVAL);
 
-	bits = 0;
-	mask = 0;
+	bits = old_mode_bits = 0;
+	mask = old_mode_mask = 0;
 	if (mode != -1) {
 		bits = ATTR_S1_IDX(mode);
 		mask = ATTR_S1_IDX_MASK;
@@ -8326,6 +8345,10 @@ pmap_change_props_locked(void *addr, vm_size_t size, vm_prot_t prot,
 			bits |= ATTR_S1_XN;
 		}
 	}
+	if (old_mode != -1) {
+		old_mode_bits = ATTR_S1_IDX(old_mode);
+		old_mode_mask = ATTR_S1_IDX_MASK;
+	}
 	if (prot != VM_PROT_NONE) {
 		/* Don't mark the DMAP as executable. It never is on arm64. */
 		if (VIRT_IN_DMAP(base)) {
@@ -8353,11 +8376,14 @@ pmap_change_props_locked(void *addr, vm_size_t size, vm_prot_t prot,
 		if (ptep == NULL && !skip_unmapped) {
 			return (EINVAL);
 		} else if ((ptep == NULL && skip_unmapped) ||
-		    (pmap_load(ptep) & mask) == bits) {
+		    (pmap_load(ptep) & mask) == bits ||
+		    (pmap_load(ptep) & old_mode_mask) != old_mode_bits) {
 			/*
-			 * We already have the correct attribute or there
-			 * is no memory mapped at this address and we are
-			 * skipping unmapped memory.
+			 * We already have one of the following meaning
+			 * we can skip this memory region::
+			 *  - No memory mapped at this address
+			 *  - The new attributes are already set
+			 *  - The expected attributes are incorrect
 			 */
 			switch (lvl) {
 			default:
@@ -8487,12 +8513,24 @@ pmap_change_props_locked(void *addr, vm_size_t size, vm_prot_t prot,
 
 			pa = PTE_TO_PHYS(pte);
 			if (!VIRT_IN_DMAP(tmpva) && PHYS_IN_DMAP(pa)) {
+				int dmap_mode;
+
+				/*
+				 * When booting on HW with MTE enabled we may
+				 * need to swap to a tagged type for the DMAP
+				 * to allow tags to be set through it.
+				 */
+				if (mode == VM_MEMATTR_WRITE_BACK)
+					dmap_mode = dmap_attr;
+				else
+					dmap_mode = mode;
+
 				/*
 				 * Keep the DMAP memory in sync.
 				 */
 				rv = pmap_change_props_locked(
 				    PHYS_TO_DMAP(pa), pte_size,
-				    prot, mode, true);
+				    prot, dmap_mode, old_mode, true);
 				if (rv != 0)
 					return (rv);
 			}
diff --git a/sys/arm64/include/pmap.h b/sys/arm64/include/pmap.h
index 00b54a874e12..1d90e8d472f2 100644
--- a/sys/arm64/include/pmap.h
+++ b/sys/arm64/include/pmap.h
@@ -148,6 +148,7 @@ void	pmap_activate_vm(pmap_t);
 void	pmap_bootstrap_dmap(vm_size_t);
 void	pmap_bootstrap(void);
 int	pmap_change_attr(void *va, vm_size_t size, int mode);
+int	pmap_change_dmap_attr(int);
 int	pmap_change_prot(void *va, vm_size_t size, vm_prot_t prot);
 void	pmap_kenter(vm_offset_t sva, vm_size_t size, vm_paddr_t pa, int mode);
 void	pmap_kenter_device(vm_offset_t, vm_size_t, vm_paddr_t);


home | help

Want to link to this message? Use this
URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?6a170c99.27186.58925c24>