[PATCH RFC 04/18] x86/mm/pat: use page table accessors for effective RW/NX bits

From: Mike Rapoport (Microsoft)

Date: Tue Jul 21 2026 - 14:00:52 EST


In preparation to moving core parts of change_page_attr() to common
code, replace open coded checks for _PAGE_RW and _PAGE_NX bits in
lookup_address_in_pgd_attr() with pXd_write() and pXd_exec() accessors.

Add x86 implementation of pXd_write() and pXd_exec() accessors and
provide generic stubs in include/linux/pgtable.h.

The stubs follow the existing pattern and BUG() if they are called.

No functional change intended.

Assisted-by: Copilot:claude-opus-4.8
Signed-off-by: Mike Rapoport (Microsoft) <rppt@xxxxxxxxxx>
---
arch/x86/include/asm/pgtable.h | 36 ++++++++++++++++++++++++++++++++++++
arch/x86/mm/pat/set_memory.c | 16 ++++++++--------
include/linux/pgtable.h | 40 ++++++++++++++++++++++++++++++++++++++++
3 files changed, 84 insertions(+), 8 deletions(-)

diff --git a/arch/x86/include/asm/pgtable.h b/arch/x86/include/asm/pgtable.h
index ac295ca6c92f..497aaf08ad36 100644
--- a/arch/x86/include/asm/pgtable.h
+++ b/arch/x86/include/asm/pgtable.h
@@ -227,6 +227,42 @@ static inline int pud_write(pud_t pud)
return pud_flags(pud) & _PAGE_RW;
}

+#define p4d_write p4d_write
+static inline int p4d_write(p4d_t p4d)
+{
+ return p4d_flags(p4d) & _PAGE_RW;
+}
+
+#define pgd_write pgd_write
+static inline int pgd_write(pgd_t pgd)
+{
+ return pgd_flags(pgd) & _PAGE_RW;
+}
+
+#define pmd_exec pmd_exec
+static inline int pmd_exec(pmd_t pmd)
+{
+ return !(pmd_flags(pmd) & _PAGE_NX);
+}
+
+#define pud_exec pud_exec
+static inline int pud_exec(pud_t pud)
+{
+ return !(pud_flags(pud) & _PAGE_NX);
+}
+
+#define p4d_exec p4d_exec
+static inline int p4d_exec(p4d_t p4d)
+{
+ return !(p4d_flags(p4d) & _PAGE_NX);
+}
+
+#define pgd_exec pgd_exec
+static inline int pgd_exec(pgd_t pgd)
+{
+ return !(pgd_flags(pgd) & _PAGE_NX);
+}
+
static inline int pte_huge(pte_t pte)
{
return pte_flags(pte) & _PAGE_PSE;
diff --git a/arch/x86/mm/pat/set_memory.c b/arch/x86/mm/pat/set_memory.c
index 328805933d4d..8a1782f5de3e 100644
--- a/arch/x86/mm/pat/set_memory.c
+++ b/arch/x86/mm/pat/set_memory.c
@@ -729,8 +729,8 @@ pte_t *lookup_address_in_pgd_attr(pgd_t *pgd, unsigned long address,
return NULL;

*level = PGTABLE_LEVEL_P4D;
- *nx |= pgd_flags(*pgd) & _PAGE_NX;
- *rw &= !!(pgd_flags(*pgd) & _PAGE_RW);
+ *nx |= !pgd_exec(*pgd);
+ *rw &= !!(pgd_write(*pgd));

p4d = p4d_offset(pgd, address);
if (p4d_none(*p4d))
@@ -740,8 +740,8 @@ pte_t *lookup_address_in_pgd_attr(pgd_t *pgd, unsigned long address,
return (pte_t *)p4d;

*level = PGTABLE_LEVEL_PUD;
- *nx |= p4d_flags(*p4d) & _PAGE_NX;
- *rw &= !!(p4d_flags(*p4d) & _PAGE_RW);
+ *nx |= !p4d_exec(*p4d);
+ *rw &= !!(p4d_write(*p4d));

pud = pud_offset(p4d, address);
if (pud_none(*pud))
@@ -751,8 +751,8 @@ pte_t *lookup_address_in_pgd_attr(pgd_t *pgd, unsigned long address,
return (pte_t *)pud;

*level = PGTABLE_LEVEL_PMD;
- *nx |= pud_flags(*pud) & _PAGE_NX;
- *rw &= !!(pud_flags(*pud) & _PAGE_RW);
+ *nx |= !pud_exec(*pud);
+ *rw &= !!(pud_write(*pud));

pmd = pmd_offset(pud, address);
if (pmd_none(*pmd))
@@ -762,8 +762,8 @@ pte_t *lookup_address_in_pgd_attr(pgd_t *pgd, unsigned long address,
return (pte_t *)pmd;

*level = PGTABLE_LEVEL_PTE;
- *nx |= pmd_flags(*pmd) & _PAGE_NX;
- *rw &= !!(pmd_flags(*pmd) & _PAGE_RW);
+ *nx |= !pmd_exec(*pmd);
+ *rw &= !!(pmd_write(*pmd));

return pte_offset_kernel(pmd, address);
}
diff --git a/include/linux/pgtable.h b/include/linux/pgtable.h
index 3889bc2a1f76..4b42ac5c27d9 100644
--- a/include/linux/pgtable.h
+++ b/include/linux/pgtable.h
@@ -2105,6 +2105,46 @@ static inline int pud_write(pud_t pud)
}
#endif /* pud_write */

+#ifndef p4d_write
+static inline int p4d_write(p4d_t p4d)
+{
+ BUG();
+ return 0;
+}
+#endif /* p4d_write */
+
+#ifndef pmd_exec
+static inline int pmd_exec(pmd_t pmd)
+{
+ BUG();
+ return 0;
+}
+#endif /* pmd_exec */
+
+#ifndef pud_exec
+static inline int pud_exec(pud_t pud)
+{
+ BUG();
+ return 0;
+}
+#endif /* pud_exec */
+
+#ifndef p4d_exec
+static inline int p4d_exec(p4d_t p4d)
+{
+ BUG();
+ return 0;
+}
+#endif /* p4d_exec */
+
+#ifndef pgd_exec
+static inline int pgd_exec(pgd_t pgd)
+{
+ BUG();
+ return 0;
+}
+#endif /* pgd_exec */
+
#if !defined(CONFIG_TRANSPARENT_HUGEPAGE) || \
!defined(CONFIG_HAVE_ARCH_TRANSPARENT_HUGEPAGE_PUD)
static inline int pud_trans_huge(pud_t pud)

--
2.53.0