git: 886190fa267e - stable/13 - Handle table attributes in the arm64 kernel map

From: Andrew Turner <andrew_at_FreeBSD.org>
Date: Wed, 29 Dec 2021 10:39:52 UTC
The branch stable/13 has been updated by andrew:

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

commit 886190fa267ecae634481982efd4a85688b7e6fe
Author:     Andrew Turner <andrew@FreeBSD.org>
AuthorDate: 2021-12-07 14:23:13 +0000
Commit:     Andrew Turner <andrew@FreeBSD.org>
CommitDate: 2021-12-29 10:05:59 +0000

    Handle table attributes in the arm64 kernel map
    
    When getting the arm64 kernel maps sysctl we should look at the table
    attributes as well as the block/page attributes. These attributes are
    different to the last level attributes so need to be translated.
    
    The previous code assumed the table and block/page attributes are
    identical, however this is not the case. Handle the difference by
    extracting the code into new helper functions & calling them as needed
    based on the entry type being checked.
    
    Reviewed by:    markj
    Sponsored by:   The FreeBSD Foundation
    Differential Revision: https://reviews.freebsd.org/D33321
    
    (cherry picked from commit 8d0b41b058795dcb0270ca0abcbf92289563c3ed)
---
 sys/arm64/arm64/pmap.c | 47 +++++++++++++++++++++++++++++++++++++++--------
 1 file changed, 39 insertions(+), 8 deletions(-)

diff --git a/sys/arm64/arm64/pmap.c b/sys/arm64/arm64/pmap.c
index 17e76c0d5a41..d4cebf6a8956 100644
--- a/sys/arm64/arm64/pmap.c
+++ b/sys/arm64/arm64/pmap.c
@@ -7215,6 +7215,30 @@ sysctl_kmaps_reinit(struct pmap_kernel_map_range *range, vm_offset_t va,
 	range->attrs = attrs;
 }
 
+/* Get the block/page attributes that correspond to the table attributes */
+static pt_entry_t
+sysctl_kmaps_table_attrs(pd_entry_t table)
+{
+	pt_entry_t attrs;
+
+	attrs = 0;
+	if ((table & TATTR_UXN_TABLE) != 0)
+		attrs |= ATTR_S1_UXN;
+	if ((table & TATTR_PXN_TABLE) != 0)
+		attrs |= ATTR_S1_PXN;
+	if ((table & TATTR_AP_TABLE_RO) != 0)
+		attrs |= ATTR_S1_AP(ATTR_S1_AP_RO);
+
+	return (attrs);
+}
+
+/* Read the block/page attributes we care about */
+static pt_entry_t
+sysctl_kmaps_block_attrs(pt_entry_t block)
+{
+	return (block & (ATTR_S1_AP_MASK | ATTR_S1_XN | ATTR_S1_IDX_MASK));
+}
+
 /*
  * Given a leaf PTE, derive the mapping's attributes.  If they do not match
  * those of the current run, dump the address range and its attributes, and
@@ -7227,15 +7251,22 @@ sysctl_kmaps_check(struct sbuf *sb, struct pmap_kernel_map_range *range,
 {
 	pt_entry_t attrs;
 
-	attrs = l0e & (ATTR_S1_AP_MASK | ATTR_S1_XN);
-	attrs |= l1e & (ATTR_S1_AP_MASK | ATTR_S1_XN);
-	if ((l1e & ATTR_DESCR_MASK) == L1_BLOCK)
-		attrs |= l1e & ATTR_S1_IDX_MASK;
-	attrs |= l2e & (ATTR_S1_AP_MASK | ATTR_S1_XN);
-	if ((l2e & ATTR_DESCR_MASK) == L2_BLOCK)
-		attrs |= l2e & ATTR_S1_IDX_MASK;
-	attrs |= l3e & (ATTR_S1_AP_MASK | ATTR_S1_XN | ATTR_S1_IDX_MASK);
+	attrs = sysctl_kmaps_table_attrs(l0e);
+
+	if ((l1e & ATTR_DESCR_TYPE_MASK) == ATTR_DESCR_TYPE_BLOCK) {
+		attrs |= sysctl_kmaps_block_attrs(l1e);
+		goto done;
+	}
+	attrs |= sysctl_kmaps_table_attrs(l1e);
+
+	if ((l2e & ATTR_DESCR_TYPE_MASK) == ATTR_DESCR_TYPE_BLOCK) {
+		attrs |= sysctl_kmaps_block_attrs(l2e);
+		goto done;
+	}
+	attrs |= sysctl_kmaps_table_attrs(l2e);
+	attrs |= sysctl_kmaps_block_attrs(l3e);
 
+done:
 	if (range->sva > va || !sysctl_kmaps_match(range, attrs)) {
 		sysctl_kmaps_dump(sb, range, va);
 		sysctl_kmaps_reinit(range, va, attrs);