linuxppc-dev.lists.ozlabs.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v2 00/37] Implement execute-only protection on powerpc
@ 2023-09-25 18:31 Christophe Leroy
  2023-09-25 18:31 ` [PATCH v2 01/37] powerpc/8xx: Fix pte_access_permitted() for PAGE_NONE Christophe Leroy
                   ` (38 more replies)
  0 siblings, 39 replies; 50+ messages in thread
From: Christophe Leroy @ 2023-09-25 18:31 UTC (permalink / raw)
  To: Michael Ellerman, Nicholas Piggin; +Cc: linuxppc-dev, linux-kernel

This series reworks _PAGE_FLAGS on all platforms in order
to implement execute-only protection on all powerpc.

For all targets except 40x and 604 it will be a real execute-only
protection as the hardware and/or software allows a distinct protection.

For 40x and 604 that's a poor's man execute-only protection in the
way that once the page is in the TLB it can be executed. But it's
better than nothing and allows to have a similar implementation for
all sorts of powerpc.

Patches 1 and 2 are fixes that should also be back-ported to stable
version.

Patches 3 to 7 are generic trivial cleanups.

Patches 8 to 19 are a cleanup of pgtable.h for nohash. Main purpose
is to refactor a lot of common code between nohash/32 and nohash/64.

Patches 20 to 37 do the real work on PAGE flags in order to
switch all platforms to _PAGE_READ and _PAGE_WRITE like book3s/64
today. Once that is done it is easy to implement execute-only
protection.

Patch 1 to 19 were already sent-out as v1 of series
named "cleanup/refactor pgtable.h". Problems reported by robots
are fixed here.

Christophe Leroy (37):
  powerpc/8xx: Fix pte_access_permitted() for PAGE_NONE
  powerpc/64e: Fix wrong test in __ptep_test_and_clear_young()
  powerpc/40x: Remove stale PTE_ATOMIC_UPDATES macro
  powerpc: Remove pte_ERROR()
  powerpc: Deduplicate prototypes of ptep_set_access_flags() and
    phys_mem_access_prot()
  powerpc: Refactor update_mmu_cache_range()
  powerpc: Untangle fixmap.h and pgtable.h and mmu.h
  powerpc/nohash: Remove {pte/pmd}_protnone()
  powerpc/nohash: Refactor declaration of {map/unmap}_kernel_page()
  powerpc/nohash: Move 8xx version of pte_update() into pte-8xx.h
  powerpc/nohash: Replace #ifdef CONFIG_44x by IS_ENABLED(CONFIG_44x) in
    pgtable.h
  powerpc/nohash: Refactor pte_update()
  powerpc/nohash: Refactor checking of no-change in pte_update()
  powerpc/nohash: Deduplicate _PAGE_CHG_MASK
  powerpc/nohash: Deduplicate pte helpers
  powerpc/nohash: Refactor ptep_test_and_clear_young()
  powerpc/nohash: Deduplicate ptep_set_wrprotect() and
    ptep_get_and_clear()
  powerpc/nohash: Refactor pte_clear()
  powerpc/nohash: Refactor __ptep_set_access_flags()
  powerpc/e500: Simplify pte_mkexec()
  powerpc: Implement and use pgprot_nx()
  powerpc: Fail ioremap() instead of silently ignoring flags when
    PAGE_USER is set
  powerpc: Remove pte_mkuser() and pte_mkpriviledged()
  powerpc: Rely on address instead of pte_user()
  powerpc: Refactor permission masks used for __P/__S table and kernel
    memory flags
  powerpc/8xx: Use generic permission masks
  powerpc/64s: Use generic permission masks
  powerpc/nohash: Add _PAGE_WRITE to supplement _PAGE_RW
  powerpc/nohash: Replace pte_user() by pte_read()
  powerpc/e500: Introduce _PAGE_READ and remove _PAGE_USER
  powerpc/44x: Introduce _PAGE_READ and remove _PAGE_USER
  powerpc/40x: Introduce _PAGE_READ and remove _PAGE_USER
  powerpc/32s: Add _PAGE_WRITE to supplement _PAGE_RW
  powerpc/32s: Introduce _PAGE_READ and remove _PAGE_USER
  powerpc/ptdump: Display _PAGE_READ and _PAGE_WRITE
  powerpc: Finally remove _PAGE_USER
  powerpc: Support execute-only on all powerpc

 arch/powerpc/include/asm/book3s/32/pgtable.h  |  83 +++----
 arch/powerpc/include/asm/book3s/64/pgtable.h  |  35 +--
 arch/powerpc/include/asm/book3s/pgtable.h     |  33 ---
 arch/powerpc/include/asm/fixmap.h             |  16 +-
 arch/powerpc/include/asm/nohash/32/mmu-8xx.h  |   1 -
 arch/powerpc/include/asm/nohash/32/pgtable.h  | 201 +---------------
 arch/powerpc/include/asm/nohash/32/pte-40x.h  |  21 +-
 arch/powerpc/include/asm/nohash/32/pte-44x.h  |  20 +-
 arch/powerpc/include/asm/nohash/32/pte-85xx.h |  20 +-
 arch/powerpc/include/asm/nohash/32/pte-8xx.h  |  99 +++++---
 arch/powerpc/include/asm/nohash/64/pgtable.h  | 120 +---------
 arch/powerpc/include/asm/nohash/pgtable.h     | 216 ++++++++++++------
 arch/powerpc/include/asm/nohash/pte-e500.h    |  41 +---
 arch/powerpc/include/asm/pgtable-masks.h      |  32 +++
 arch/powerpc/include/asm/pgtable.h            |  35 +++
 arch/powerpc/kernel/head_40x.S                |  19 +-
 arch/powerpc/kernel/head_44x.S                |  40 ++--
 arch/powerpc/kernel/head_85xx.S               |  12 +-
 arch/powerpc/kernel/head_book3s_32.S          |  63 ++---
 arch/powerpc/mm/book3s32/hash_low.S           |  32 ++-
 arch/powerpc/mm/book3s32/mmu.c                |   6 +-
 arch/powerpc/mm/book3s64/pgtable.c            |  10 +-
 arch/powerpc/mm/fault.c                       |   9 +-
 arch/powerpc/mm/init_32.c                     |   1 +
 arch/powerpc/mm/ioremap.c                     |   6 +-
 arch/powerpc/mm/mem.c                         |   1 +
 arch/powerpc/mm/nohash/40x.c                  |  19 +-
 arch/powerpc/mm/nohash/8xx.c                  |   2 +
 arch/powerpc/mm/nohash/book3e_pgtable.c       |   2 +-
 arch/powerpc/mm/nohash/e500.c                 |   6 +-
 arch/powerpc/mm/nohash/e500_hugetlbpage.c     |   3 +-
 arch/powerpc/mm/pgtable.c                     |  26 +--
 arch/powerpc/mm/ptdump/8xx.c                  |   5 -
 arch/powerpc/mm/ptdump/shared.c               |  14 +-
 arch/powerpc/platforms/83xx/misc.c            |   2 +
 arch/powerpc/platforms/8xx/cpm1.c             |   1 +
 36 files changed, 511 insertions(+), 741 deletions(-)
 create mode 100644 arch/powerpc/include/asm/pgtable-masks.h

-- 
2.41.0


^ permalink raw reply	[flat|nested] 50+ messages in thread

* [PATCH v2 01/37] powerpc/8xx: Fix pte_access_permitted() for PAGE_NONE
  2023-09-25 18:31 [PATCH v2 00/37] Implement execute-only protection on powerpc Christophe Leroy
@ 2023-09-25 18:31 ` Christophe Leroy
  2023-09-25 18:31 ` [PATCH v2 02/37] powerpc/64e: Fix wrong test in __ptep_test_and_clear_young() Christophe Leroy
                   ` (37 subsequent siblings)
  38 siblings, 0 replies; 50+ messages in thread
From: Christophe Leroy @ 2023-09-25 18:31 UTC (permalink / raw)
  To: Michael Ellerman, Nicholas Piggin; +Cc: linuxppc-dev, linux-kernel

On 8xx, PAGE_NONE is handled by setting _PAGE_NA instead of clearing
_PAGE_USER.

But then pte_user() returns 1 also for PAGE_NONE.

As _PAGE_NA prevent reads, add a specific version of pte_read()
that returns 0 when _PAGE_NA is set instead of always returning 1.

Fixes: 351750331fc1 ("powerpc/mm: Introduce _PAGE_NA")
Signed-off-by: Christophe Leroy <christophe.leroy@csgroup.eu>
---
 arch/powerpc/include/asm/nohash/32/pte-8xx.h | 7 +++++++
 arch/powerpc/include/asm/nohash/pgtable.h    | 2 ++
 2 files changed, 9 insertions(+)

diff --git a/arch/powerpc/include/asm/nohash/32/pte-8xx.h b/arch/powerpc/include/asm/nohash/32/pte-8xx.h
index 21f681ee535a..e6fe1d5731f2 100644
--- a/arch/powerpc/include/asm/nohash/32/pte-8xx.h
+++ b/arch/powerpc/include/asm/nohash/32/pte-8xx.h
@@ -94,6 +94,13 @@ static inline pte_t pte_wrprotect(pte_t pte)
 
 #define pte_wrprotect pte_wrprotect
 
+static inline int pte_read(pte_t pte)
+{
+	return (pte_val(pte) & _PAGE_RO) != _PAGE_NA;
+}
+
+#define pte_read pte_read
+
 static inline int pte_write(pte_t pte)
 {
 	return !(pte_val(pte) & _PAGE_RO);
diff --git a/arch/powerpc/include/asm/nohash/pgtable.h b/arch/powerpc/include/asm/nohash/pgtable.h
index 56ea48276356..c721478c5934 100644
--- a/arch/powerpc/include/asm/nohash/pgtable.h
+++ b/arch/powerpc/include/asm/nohash/pgtable.h
@@ -25,7 +25,9 @@ static inline int pte_write(pte_t pte)
 	return pte_val(pte) & _PAGE_RW;
 }
 #endif
+#ifndef pte_read
 static inline int pte_read(pte_t pte)		{ return 1; }
+#endif
 static inline int pte_dirty(pte_t pte)		{ return pte_val(pte) & _PAGE_DIRTY; }
 static inline int pte_special(pte_t pte)	{ return pte_val(pte) & _PAGE_SPECIAL; }
 static inline int pte_none(pte_t pte)		{ return (pte_val(pte) & ~_PTE_NONE_MASK) == 0; }
-- 
2.41.0


^ permalink raw reply related	[flat|nested] 50+ messages in thread

* [PATCH v2 02/37] powerpc/64e: Fix wrong test in __ptep_test_and_clear_young()
  2023-09-25 18:31 [PATCH v2 00/37] Implement execute-only protection on powerpc Christophe Leroy
  2023-09-25 18:31 ` [PATCH v2 01/37] powerpc/8xx: Fix pte_access_permitted() for PAGE_NONE Christophe Leroy
@ 2023-09-25 18:31 ` Christophe Leroy
  2023-09-25 18:31 ` [PATCH v2 03/37] powerpc/40x: Remove stale PTE_ATOMIC_UPDATES macro Christophe Leroy
                   ` (36 subsequent siblings)
  38 siblings, 0 replies; 50+ messages in thread
From: Christophe Leroy @ 2023-09-25 18:31 UTC (permalink / raw)
  To: Michael Ellerman, Nicholas Piggin; +Cc: linuxppc-dev, linux-kernel

Commit 45201c879469 ("powerpc/nohash: Remove hash related code from
nohash headers.") replaced:

  if ((pte_val(*ptep) & (_PAGE_ACCESSED | _PAGE_HASHPTE)) == 0)
	return 0;

By:

  if (pte_young(*ptep))
	return 0;

But it should be:

  if (!pte_young(*ptep))
	return 0;

Fix it.

Fixes: 45201c879469 ("powerpc/nohash: Remove hash related code from nohash headers.")
Signed-off-by: Christophe Leroy <christophe.leroy@csgroup.eu>
---
 arch/powerpc/include/asm/nohash/64/pgtable.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/arch/powerpc/include/asm/nohash/64/pgtable.h b/arch/powerpc/include/asm/nohash/64/pgtable.h
index 5cd9acf58a7d..eb6891e34cbd 100644
--- a/arch/powerpc/include/asm/nohash/64/pgtable.h
+++ b/arch/powerpc/include/asm/nohash/64/pgtable.h
@@ -197,7 +197,7 @@ static inline int __ptep_test_and_clear_young(struct mm_struct *mm,
 {
 	unsigned long old;
 
-	if (pte_young(*ptep))
+	if (!pte_young(*ptep))
 		return 0;
 	old = pte_update(mm, addr, ptep, _PAGE_ACCESSED, 0, 0);
 	return (old & _PAGE_ACCESSED) != 0;
-- 
2.41.0


^ permalink raw reply related	[flat|nested] 50+ messages in thread

* [PATCH v2 03/37] powerpc/40x: Remove stale PTE_ATOMIC_UPDATES macro
  2023-09-25 18:31 [PATCH v2 00/37] Implement execute-only protection on powerpc Christophe Leroy
  2023-09-25 18:31 ` [PATCH v2 01/37] powerpc/8xx: Fix pte_access_permitted() for PAGE_NONE Christophe Leroy
  2023-09-25 18:31 ` [PATCH v2 02/37] powerpc/64e: Fix wrong test in __ptep_test_and_clear_young() Christophe Leroy
@ 2023-09-25 18:31 ` Christophe Leroy
  2023-09-25 18:31 ` [PATCH v2 04/37] powerpc: Remove pte_ERROR() Christophe Leroy
                   ` (35 subsequent siblings)
  38 siblings, 0 replies; 50+ messages in thread
From: Christophe Leroy @ 2023-09-25 18:31 UTC (permalink / raw)
  To: Michael Ellerman, Nicholas Piggin; +Cc: linuxppc-dev, linux-kernel

40x TLB handlers were reworked by commit 2c74e2586bb9 ("powerpc/40x:
Rework 40x PTE access and TLB miss") to not require PTE_ATOMIC_UPDATES
anymore.

Then commit 4e1df545e2fa ("powerpc/pgtable: Drop PTE_ATOMIC_UPDATES")
removed all code related to PTE_ATOMIC_UPDATES.

Remove left over PTE_ATOMIC_UPDATES macro.

Fixes: 2c74e2586bb9 ("powerpc/40x: Rework 40x PTE access and TLB miss")
Signed-off-by: Christophe Leroy <christophe.leroy@csgroup.eu>
---
 arch/powerpc/include/asm/nohash/32/pte-40x.h | 3 ---
 1 file changed, 3 deletions(-)

diff --git a/arch/powerpc/include/asm/nohash/32/pte-40x.h b/arch/powerpc/include/asm/nohash/32/pte-40x.h
index 6fe46e754556..0b4e5f8ce3e8 100644
--- a/arch/powerpc/include/asm/nohash/32/pte-40x.h
+++ b/arch/powerpc/include/asm/nohash/32/pte-40x.h
@@ -69,9 +69,6 @@
 
 #define _PTE_NONE_MASK	0
 
-/* Until my rework is finished, 40x still needs atomic PTE updates */
-#define PTE_ATOMIC_UPDATES	1
-
 #define _PAGE_BASE_NC	(_PAGE_PRESENT | _PAGE_ACCESSED)
 #define _PAGE_BASE	(_PAGE_BASE_NC)
 
-- 
2.41.0


^ permalink raw reply related	[flat|nested] 50+ messages in thread

* [PATCH v2 04/37] powerpc: Remove pte_ERROR()
  2023-09-25 18:31 [PATCH v2 00/37] Implement execute-only protection on powerpc Christophe Leroy
                   ` (2 preceding siblings ...)
  2023-09-25 18:31 ` [PATCH v2 03/37] powerpc/40x: Remove stale PTE_ATOMIC_UPDATES macro Christophe Leroy
@ 2023-09-25 18:31 ` Christophe Leroy
  2023-09-25 18:31 ` [PATCH v2 05/37] powerpc: Deduplicate prototypes of ptep_set_access_flags() and phys_mem_access_prot() Christophe Leroy
                   ` (34 subsequent siblings)
  38 siblings, 0 replies; 50+ messages in thread
From: Christophe Leroy @ 2023-09-25 18:31 UTC (permalink / raw)
  To: Michael Ellerman, Nicholas Piggin; +Cc: linuxppc-dev, linux-kernel

pte_ERROR() is used neither in powerpc code nor in common mm code.

Remove it.

Signed-off-by: Christophe Leroy <christophe.leroy@csgroup.eu>
---
 arch/powerpc/include/asm/book3s/32/pgtable.h | 3 ---
 arch/powerpc/include/asm/book3s/64/pgtable.h | 2 --
 arch/powerpc/include/asm/nohash/32/pgtable.h | 3 ---
 arch/powerpc/include/asm/nohash/64/pgtable.h | 2 --
 4 files changed, 10 deletions(-)

diff --git a/arch/powerpc/include/asm/book3s/32/pgtable.h b/arch/powerpc/include/asm/book3s/32/pgtable.h
index 9b13eb14e21b..543c3691839b 100644
--- a/arch/powerpc/include/asm/book3s/32/pgtable.h
+++ b/arch/powerpc/include/asm/book3s/32/pgtable.h
@@ -224,9 +224,6 @@ void unmap_kernel_page(unsigned long va);
 /* Bits to mask out from a PGD to get to the PUD page */
 #define PGD_MASKED_BITS		0
 
-#define pte_ERROR(e) \
-	pr_err("%s:%d: bad pte %llx.\n", __FILE__, __LINE__, \
-		(unsigned long long)pte_val(e))
 #define pgd_ERROR(e) \
 	pr_err("%s:%d: bad pgd %08lx.\n", __FILE__, __LINE__, pgd_val(e))
 /*
diff --git a/arch/powerpc/include/asm/book3s/64/pgtable.h b/arch/powerpc/include/asm/book3s/64/pgtable.h
index 5c497c862d75..7c4ad1e03a49 100644
--- a/arch/powerpc/include/asm/book3s/64/pgtable.h
+++ b/arch/powerpc/include/asm/book3s/64/pgtable.h
@@ -1014,8 +1014,6 @@ static inline pmd_t *pud_pgtable(pud_t pud)
 	return (pmd_t *)__va(pud_val(pud) & ~PUD_MASKED_BITS);
 }
 
-#define pte_ERROR(e) \
-	pr_err("%s:%d: bad pte %08lx.\n", __FILE__, __LINE__, pte_val(e))
 #define pmd_ERROR(e) \
 	pr_err("%s:%d: bad pmd %08lx.\n", __FILE__, __LINE__, pmd_val(e))
 #define pud_ERROR(e) \
diff --git a/arch/powerpc/include/asm/nohash/32/pgtable.h b/arch/powerpc/include/asm/nohash/32/pgtable.h
index f99c53a5f184..868aecbec8d1 100644
--- a/arch/powerpc/include/asm/nohash/32/pgtable.h
+++ b/arch/powerpc/include/asm/nohash/32/pgtable.h
@@ -55,9 +55,6 @@ extern int icache_44x_need_flush;
 
 #define USER_PTRS_PER_PGD	(TASK_SIZE / PGDIR_SIZE)
 
-#define pte_ERROR(e) \
-	pr_err("%s:%d: bad pte %llx.\n", __FILE__, __LINE__, \
-		(unsigned long long)pte_val(e))
 #define pgd_ERROR(e) \
 	pr_err("%s:%d: bad pgd %08lx.\n", __FILE__, __LINE__, pgd_val(e))
 
diff --git a/arch/powerpc/include/asm/nohash/64/pgtable.h b/arch/powerpc/include/asm/nohash/64/pgtable.h
index eb6891e34cbd..8083c04a1e6d 100644
--- a/arch/powerpc/include/asm/nohash/64/pgtable.h
+++ b/arch/powerpc/include/asm/nohash/64/pgtable.h
@@ -269,8 +269,6 @@ static inline void __ptep_set_access_flags(struct vm_area_struct *vma,
 	flush_tlb_page(vma, address);
 }
 
-#define pte_ERROR(e) \
-	pr_err("%s:%d: bad pte %08lx.\n", __FILE__, __LINE__, pte_val(e))
 #define pmd_ERROR(e) \
 	pr_err("%s:%d: bad pmd %08lx.\n", __FILE__, __LINE__, pmd_val(e))
 #define pgd_ERROR(e) \
-- 
2.41.0


^ permalink raw reply related	[flat|nested] 50+ messages in thread

* [PATCH v2 05/37] powerpc: Deduplicate prototypes of ptep_set_access_flags() and phys_mem_access_prot()
  2023-09-25 18:31 [PATCH v2 00/37] Implement execute-only protection on powerpc Christophe Leroy
                   ` (3 preceding siblings ...)
  2023-09-25 18:31 ` [PATCH v2 04/37] powerpc: Remove pte_ERROR() Christophe Leroy
@ 2023-09-25 18:31 ` Christophe Leroy
  2023-09-25 18:31 ` [PATCH v2 06/37] powerpc: Refactor update_mmu_cache_range() Christophe Leroy
                   ` (33 subsequent siblings)
  38 siblings, 0 replies; 50+ messages in thread
From: Christophe Leroy @ 2023-09-25 18:31 UTC (permalink / raw)
  To: Michael Ellerman, Nicholas Piggin; +Cc: linuxppc-dev, linux-kernel

Prototypes of ptep_set_access_flags() and phys_mem_access_prot() are identical
for book3s and nohash.

Deduplicate them.

Signed-off-by: Christophe Leroy <christophe.leroy@csgroup.eu>
---
 arch/powerpc/include/asm/book3s/pgtable.h |  9 ---------
 arch/powerpc/include/asm/nohash/pgtable.h | 10 ----------
 arch/powerpc/include/asm/pgtable.h        | 10 ++++++++++
 3 files changed, 10 insertions(+), 19 deletions(-)

diff --git a/arch/powerpc/include/asm/book3s/pgtable.h b/arch/powerpc/include/asm/book3s/pgtable.h
index 3b7bd36a2321..6f4578daea6c 100644
--- a/arch/powerpc/include/asm/book3s/pgtable.h
+++ b/arch/powerpc/include/asm/book3s/pgtable.h
@@ -9,15 +9,6 @@
 #endif
 
 #ifndef __ASSEMBLY__
-#define __HAVE_ARCH_PTEP_SET_ACCESS_FLAGS
-extern int ptep_set_access_flags(struct vm_area_struct *vma, unsigned long address,
-				 pte_t *ptep, pte_t entry, int dirty);
-
-struct file;
-extern pgprot_t phys_mem_access_prot(struct file *file, unsigned long pfn,
-				     unsigned long size, pgprot_t vma_prot);
-#define __HAVE_PHYS_MEM_ACCESS_PROT
-
 void __update_mmu_cache(struct vm_area_struct *vma, unsigned long address, pte_t *ptep);
 
 /*
diff --git a/arch/powerpc/include/asm/nohash/pgtable.h b/arch/powerpc/include/asm/nohash/pgtable.h
index c721478c5934..5b6647fb398b 100644
--- a/arch/powerpc/include/asm/nohash/pgtable.h
+++ b/arch/powerpc/include/asm/nohash/pgtable.h
@@ -207,11 +207,6 @@ static inline void __set_pte_at(struct mm_struct *mm, unsigned long addr,
 		mb();
 }
 
-
-#define __HAVE_ARCH_PTEP_SET_ACCESS_FLAGS
-extern int ptep_set_access_flags(struct vm_area_struct *vma, unsigned long address,
-				 pte_t *ptep, pte_t entry, int dirty);
-
 /*
  * Macro to mark a page protection value as "uncacheable".
  */
@@ -240,11 +235,6 @@ extern int ptep_set_access_flags(struct vm_area_struct *vma, unsigned long addre
 
 #define pgprot_writecombine pgprot_noncached_wc
 
-struct file;
-extern pgprot_t phys_mem_access_prot(struct file *file, unsigned long pfn,
-				     unsigned long size, pgprot_t vma_prot);
-#define __HAVE_PHYS_MEM_ACCESS_PROT
-
 #ifdef CONFIG_HUGETLB_PAGE
 static inline int hugepd_ok(hugepd_t hpd)
 {
diff --git a/arch/powerpc/include/asm/pgtable.h b/arch/powerpc/include/asm/pgtable.h
index d0ee46de248e..bcdbdeda65d3 100644
--- a/arch/powerpc/include/asm/pgtable.h
+++ b/arch/powerpc/include/asm/pgtable.h
@@ -110,6 +110,16 @@ void mark_initmem_nx(void);
 static inline void mark_initmem_nx(void) { }
 #endif
 
+#define __HAVE_ARCH_PTEP_SET_ACCESS_FLAGS
+int ptep_set_access_flags(struct vm_area_struct *vma, unsigned long address,
+			  pte_t *ptep, pte_t entry, int dirty);
+
+struct file;
+pgprot_t phys_mem_access_prot(struct file *file, unsigned long pfn,
+			      unsigned long size, pgprot_t vma_prot);
+#define __HAVE_PHYS_MEM_ACCESS_PROT
+
+
 /*
  * When used, PTE_FRAG_NR is defined in subarch pgtable.h
  * so we are sure it is included when arriving here.
-- 
2.41.0


^ permalink raw reply related	[flat|nested] 50+ messages in thread

* [PATCH v2 06/37] powerpc: Refactor update_mmu_cache_range()
  2023-09-25 18:31 [PATCH v2 00/37] Implement execute-only protection on powerpc Christophe Leroy
                   ` (4 preceding siblings ...)
  2023-09-25 18:31 ` [PATCH v2 05/37] powerpc: Deduplicate prototypes of ptep_set_access_flags() and phys_mem_access_prot() Christophe Leroy
@ 2023-09-25 18:31 ` Christophe Leroy
  2023-09-25 18:31 ` [PATCH v2 07/37] powerpc: Untangle fixmap.h and pgtable.h and mmu.h Christophe Leroy
                   ` (32 subsequent siblings)
  38 siblings, 0 replies; 50+ messages in thread
From: Christophe Leroy @ 2023-09-25 18:31 UTC (permalink / raw)
  To: Michael Ellerman, Nicholas Piggin; +Cc: linuxppc-dev, linux-kernel

On nohash, this function voids except for E500 with hugepages.

On book3s, this function is for hash MMUs only.

Combine those tests and rename E500 update_mmu_cache_range()
as __update_mmu_cache() which gets called by
update_mmu_cache_range().

Signed-off-by: Christophe Leroy <christophe.leroy@csgroup.eu>
---
v2: Fix the logic
---
 arch/powerpc/include/asm/book3s/pgtable.h | 24 -----------------------
 arch/powerpc/include/asm/nohash/pgtable.h | 15 --------------
 arch/powerpc/include/asm/pgtable.h        | 19 ++++++++++++++++++
 arch/powerpc/mm/nohash/e500_hugetlbpage.c |  3 +--
 4 files changed, 20 insertions(+), 41 deletions(-)

diff --git a/arch/powerpc/include/asm/book3s/pgtable.h b/arch/powerpc/include/asm/book3s/pgtable.h
index 6f4578daea6c..f42d68c6b314 100644
--- a/arch/powerpc/include/asm/book3s/pgtable.h
+++ b/arch/powerpc/include/asm/book3s/pgtable.h
@@ -8,28 +8,4 @@
 #include <asm/book3s/32/pgtable.h>
 #endif
 
-#ifndef __ASSEMBLY__
-void __update_mmu_cache(struct vm_area_struct *vma, unsigned long address, pte_t *ptep);
-
-/*
- * This gets called at the end of handling a page fault, when
- * the kernel has put a new PTE into the page table for the process.
- * We use it to ensure coherency between the i-cache and d-cache
- * for the page which has just been mapped in.
- * On machines which use an MMU hash table, we use this to put a
- * corresponding HPTE into the hash table ahead of time, instead of
- * waiting for the inevitable extra hash-table miss exception.
- */
-static inline void update_mmu_cache_range(struct vm_fault *vmf,
-		struct vm_area_struct *vma, unsigned long address,
-		pte_t *ptep, unsigned int nr)
-{
-	if (IS_ENABLED(CONFIG_PPC32) && !mmu_has_feature(MMU_FTR_HPTE_TABLE))
-		return;
-	if (radix_enabled())
-		return;
-	__update_mmu_cache(vma, address, ptep);
-}
-
-#endif /* __ASSEMBLY__ */
 #endif
diff --git a/arch/powerpc/include/asm/nohash/pgtable.h b/arch/powerpc/include/asm/nohash/pgtable.h
index 5b6647fb398b..a9056f4fad48 100644
--- a/arch/powerpc/include/asm/nohash/pgtable.h
+++ b/arch/powerpc/include/asm/nohash/pgtable.h
@@ -259,20 +259,5 @@ static inline int pud_huge(pud_t pud)
 #define is_hugepd(hpd)		(hugepd_ok(hpd))
 #endif
 
-/*
- * This gets called at the end of handling a page fault, when
- * the kernel has put a new PTE into the page table for the process.
- * We use it to ensure coherency between the i-cache and d-cache
- * for the page which has just been mapped in.
- */
-#if defined(CONFIG_PPC_E500) && defined(CONFIG_HUGETLB_PAGE)
-void update_mmu_cache_range(struct vm_fault *vmf, struct vm_area_struct *vma,
-		unsigned long address, pte_t *ptep, unsigned int nr);
-#else
-static inline void update_mmu_cache_range(struct vm_fault *vmf,
-		struct vm_area_struct *vma, unsigned long address,
-		pte_t *ptep, unsigned int nr) {}
-#endif
-
 #endif /* __ASSEMBLY__ */
 #endif
diff --git a/arch/powerpc/include/asm/pgtable.h b/arch/powerpc/include/asm/pgtable.h
index bcdbdeda65d3..966e7c5119f6 100644
--- a/arch/powerpc/include/asm/pgtable.h
+++ b/arch/powerpc/include/asm/pgtable.h
@@ -119,6 +119,25 @@ pgprot_t phys_mem_access_prot(struct file *file, unsigned long pfn,
 			      unsigned long size, pgprot_t vma_prot);
 #define __HAVE_PHYS_MEM_ACCESS_PROT
 
+void __update_mmu_cache(struct vm_area_struct *vma, unsigned long address, pte_t *ptep);
+
+/*
+ * This gets called at the end of handling a page fault, when
+ * the kernel has put a new PTE into the page table for the process.
+ * We use it to ensure coherency between the i-cache and d-cache
+ * for the page which has just been mapped in.
+ * On machines which use an MMU hash table, we use this to put a
+ * corresponding HPTE into the hash table ahead of time, instead of
+ * waiting for the inevitable extra hash-table miss exception.
+ */
+static inline void update_mmu_cache_range(struct vm_fault *vmf,
+		struct vm_area_struct *vma, unsigned long address,
+		pte_t *ptep, unsigned int nr)
+{
+	if ((mmu_has_feature(MMU_FTR_HPTE_TABLE) && !radix_enabled()) ||
+	    (IS_ENABLED(CONFIG_PPC_E500) && IS_ENABLED(CONFIG_HUGETLB_PAGE)))
+		__update_mmu_cache(vma, address, ptep);
+}
 
 /*
  * When used, PTE_FRAG_NR is defined in subarch pgtable.h
diff --git a/arch/powerpc/mm/nohash/e500_hugetlbpage.c b/arch/powerpc/mm/nohash/e500_hugetlbpage.c
index 6b30e40d4590..a134d28a0e4d 100644
--- a/arch/powerpc/mm/nohash/e500_hugetlbpage.c
+++ b/arch/powerpc/mm/nohash/e500_hugetlbpage.c
@@ -178,8 +178,7 @@ book3e_hugetlb_preload(struct vm_area_struct *vma, unsigned long ea, pte_t pte)
  *
  * This must always be called with the pte lock held.
  */
-void update_mmu_cache_range(struct vm_fault *vmf, struct vm_area_struct *vma,
-		unsigned long address, pte_t *ptep, unsigned int nr)
+void __update_mmu_cache(struct vm_area_struct *vma, unsigned long address, pte_t *ptep)
 {
 	if (is_vm_hugetlb_page(vma))
 		book3e_hugetlb_preload(vma, address, *ptep);
-- 
2.41.0


^ permalink raw reply related	[flat|nested] 50+ messages in thread

* [PATCH v2 07/37] powerpc: Untangle fixmap.h and pgtable.h and mmu.h
  2023-09-25 18:31 [PATCH v2 00/37] Implement execute-only protection on powerpc Christophe Leroy
                   ` (5 preceding siblings ...)
  2023-09-25 18:31 ` [PATCH v2 06/37] powerpc: Refactor update_mmu_cache_range() Christophe Leroy
@ 2023-09-25 18:31 ` Christophe Leroy
  2023-09-25 18:31 ` [PATCH v2 08/37] powerpc/nohash: Remove {pte/pmd}_protnone() Christophe Leroy
                   ` (31 subsequent siblings)
  38 siblings, 0 replies; 50+ messages in thread
From: Christophe Leroy @ 2023-09-25 18:31 UTC (permalink / raw)
  To: Michael Ellerman, Nicholas Piggin; +Cc: linuxppc-dev, linux-kernel

fixmap.h need pgtable.h for [un]map_kernel_page()

pgtable.h need fixmap.h for FIXADDR_TOP.

Untangle the two files by moving FIXADDR_TOP into pgtable.h

Also move VIRT_IMMR_BASE to fixmap.h to avoid fixmap.h in mmu.h

Signed-off-by: Christophe Leroy <christophe.leroy@csgroup.eu>
---
v2: Add asm/fixmap.h to platforms/83xx/misc.c
---
 arch/powerpc/include/asm/book3s/32/pgtable.h |  9 ++++++++-
 arch/powerpc/include/asm/book3s/64/pgtable.h |  1 +
 arch/powerpc/include/asm/fixmap.h            | 16 ++++------------
 arch/powerpc/include/asm/nohash/32/mmu-8xx.h |  1 -
 arch/powerpc/include/asm/nohash/32/pgtable.h |  9 ++++++++-
 arch/powerpc/include/asm/nohash/64/pgtable.h |  1 +
 arch/powerpc/mm/init_32.c                    |  1 +
 arch/powerpc/mm/mem.c                        |  1 +
 arch/powerpc/mm/nohash/8xx.c                 |  2 ++
 arch/powerpc/platforms/83xx/misc.c           |  2 ++
 arch/powerpc/platforms/8xx/cpm1.c            |  1 +
 11 files changed, 29 insertions(+), 15 deletions(-)

diff --git a/arch/powerpc/include/asm/book3s/32/pgtable.h b/arch/powerpc/include/asm/book3s/32/pgtable.h
index 543c3691839b..45b69ae2631e 100644
--- a/arch/powerpc/include/asm/book3s/32/pgtable.h
+++ b/arch/powerpc/include/asm/book3s/32/pgtable.h
@@ -170,7 +170,14 @@ void unmap_kernel_page(unsigned long va);
  * value (for now) on others, from where we can start layout kernel
  * virtual space that goes below PKMAP and FIXMAP
  */
-#include <asm/fixmap.h>
+
+#define FIXADDR_SIZE	0
+#ifdef CONFIG_KASAN
+#include <asm/kasan.h>
+#define FIXADDR_TOP	(KASAN_SHADOW_START - PAGE_SIZE)
+#else
+#define FIXADDR_TOP	((unsigned long)(-PAGE_SIZE))
+#endif
 
 /*
  * ioremap_bot starts at that address. Early ioremaps move down from there,
diff --git a/arch/powerpc/include/asm/book3s/64/pgtable.h b/arch/powerpc/include/asm/book3s/64/pgtable.h
index 7c4ad1e03a49..dbd545e73161 100644
--- a/arch/powerpc/include/asm/book3s/64/pgtable.h
+++ b/arch/powerpc/include/asm/book3s/64/pgtable.h
@@ -316,6 +316,7 @@ extern unsigned long pci_io_base;
 #define IOREMAP_START	(ioremap_bot)
 #define IOREMAP_END	(KERN_IO_END - FIXADDR_SIZE)
 #define FIXADDR_SIZE	SZ_32M
+#define FIXADDR_TOP	(IOREMAP_END + FIXADDR_SIZE)
 
 #ifndef __ASSEMBLY__
 
diff --git a/arch/powerpc/include/asm/fixmap.h b/arch/powerpc/include/asm/fixmap.h
index a832aeafe560..f9068dd8dfce 100644
--- a/arch/powerpc/include/asm/fixmap.h
+++ b/arch/powerpc/include/asm/fixmap.h
@@ -23,18 +23,6 @@
 #include <asm/kmap_size.h>
 #endif
 
-#ifdef CONFIG_PPC64
-#define FIXADDR_TOP	(IOREMAP_END + FIXADDR_SIZE)
-#else
-#define FIXADDR_SIZE	0
-#ifdef CONFIG_KASAN
-#include <asm/kasan.h>
-#define FIXADDR_TOP	(KASAN_SHADOW_START - PAGE_SIZE)
-#else
-#define FIXADDR_TOP	((unsigned long)(-PAGE_SIZE))
-#endif
-#endif
-
 /*
  * Here we define all the compile-time 'special' virtual
  * addresses. The point is to have a constant address at
@@ -119,5 +107,9 @@ static inline void __set_fixmap(enum fixed_addresses idx,
 
 #define __early_set_fixmap	__set_fixmap
 
+#ifdef CONFIG_PPC_8xx
+#define VIRT_IMMR_BASE (__fix_to_virt(FIX_IMMR_BASE))
+#endif
+
 #endif /* !__ASSEMBLY__ */
 #endif
diff --git a/arch/powerpc/include/asm/nohash/32/mmu-8xx.h b/arch/powerpc/include/asm/nohash/32/mmu-8xx.h
index 0e93a4728c9e..141d82e249a8 100644
--- a/arch/powerpc/include/asm/nohash/32/mmu-8xx.h
+++ b/arch/powerpc/include/asm/nohash/32/mmu-8xx.h
@@ -188,7 +188,6 @@ typedef struct {
 } mm_context_t;
 
 #define PHYS_IMMR_BASE (mfspr(SPRN_IMMR) & 0xfff80000)
-#define VIRT_IMMR_BASE (__fix_to_virt(FIX_IMMR_BASE))
 
 /* Page size definitions, common between 32 and 64-bit
  *
diff --git a/arch/powerpc/include/asm/nohash/32/pgtable.h b/arch/powerpc/include/asm/nohash/32/pgtable.h
index 868aecbec8d1..c8311ee08811 100644
--- a/arch/powerpc/include/asm/nohash/32/pgtable.h
+++ b/arch/powerpc/include/asm/nohash/32/pgtable.h
@@ -71,7 +71,14 @@ void unmap_kernel_page(unsigned long va);
  * value (for now) on others, from where we can start layout kernel
  * virtual space that goes below PKMAP and FIXMAP
  */
-#include <asm/fixmap.h>
+
+#define FIXADDR_SIZE	0
+#ifdef CONFIG_KASAN
+#include <asm/kasan.h>
+#define FIXADDR_TOP	(KASAN_SHADOW_START - PAGE_SIZE)
+#else
+#define FIXADDR_TOP	((unsigned long)(-PAGE_SIZE))
+#endif
 
 /*
  * ioremap_bot starts at that address. Early ioremaps move down from there,
diff --git a/arch/powerpc/include/asm/nohash/64/pgtable.h b/arch/powerpc/include/asm/nohash/64/pgtable.h
index 8083c04a1e6d..dee3fc654d40 100644
--- a/arch/powerpc/include/asm/nohash/64/pgtable.h
+++ b/arch/powerpc/include/asm/nohash/64/pgtable.h
@@ -57,6 +57,7 @@
 #define IOREMAP_START	(ioremap_bot)
 #define IOREMAP_END	(KERN_IO_START + KERN_IO_SIZE - FIXADDR_SIZE)
 #define FIXADDR_SIZE	SZ_32M
+#define FIXADDR_TOP	(IOREMAP_END + FIXADDR_SIZE)
 
 /*
  * Defines the address of the vmemap area, in its own region on
diff --git a/arch/powerpc/mm/init_32.c b/arch/powerpc/mm/init_32.c
index d8adc452f431..4e71dfe7d026 100644
--- a/arch/powerpc/mm/init_32.c
+++ b/arch/powerpc/mm/init_32.c
@@ -39,6 +39,7 @@
 #include <asm/hugetlb.h>
 #include <asm/kup.h>
 #include <asm/kasan.h>
+#include <asm/fixmap.h>
 
 #include <mm/mmu_decl.h>
 
diff --git a/arch/powerpc/mm/mem.c b/arch/powerpc/mm/mem.c
index 8b121df7b08f..08f3ec9d522b 100644
--- a/arch/powerpc/mm/mem.c
+++ b/arch/powerpc/mm/mem.c
@@ -26,6 +26,7 @@
 #include <asm/ftrace.h>
 #include <asm/code-patching.h>
 #include <asm/setup.h>
+#include <asm/fixmap.h>
 
 #include <mm/mmu_decl.h>
 
diff --git a/arch/powerpc/mm/nohash/8xx.c b/arch/powerpc/mm/nohash/8xx.c
index dbbfe897455d..bb9c39b449d1 100644
--- a/arch/powerpc/mm/nohash/8xx.c
+++ b/arch/powerpc/mm/nohash/8xx.c
@@ -10,6 +10,8 @@
 #include <linux/memblock.h>
 #include <linux/hugetlb.h>
 
+#include <asm/fixmap.h>
+
 #include <mm/mmu_decl.h>
 
 #define IMMR_SIZE (FIX_IMMR_SIZE << PAGE_SHIFT)
diff --git a/arch/powerpc/platforms/83xx/misc.c b/arch/powerpc/platforms/83xx/misc.c
index 2fb2a85d131f..1135c1ab923c 100644
--- a/arch/powerpc/platforms/83xx/misc.c
+++ b/arch/powerpc/platforms/83xx/misc.c
@@ -14,6 +14,8 @@
 #include <asm/io.h>
 #include <asm/hw_irq.h>
 #include <asm/ipic.h>
+#include <asm/fixmap.h>
+
 #include <sysdev/fsl_soc.h>
 #include <sysdev/fsl_pci.h>
 
diff --git a/arch/powerpc/platforms/8xx/cpm1.c b/arch/powerpc/platforms/8xx/cpm1.c
index ebb5f6a27dbf..b24d4102fbf6 100644
--- a/arch/powerpc/platforms/8xx/cpm1.c
+++ b/arch/powerpc/platforms/8xx/cpm1.c
@@ -40,6 +40,7 @@
 #include <asm/io.h>
 #include <asm/rheap.h>
 #include <asm/cpm.h>
+#include <asm/fixmap.h>
 
 #include <sysdev/fsl_soc.h>
 
-- 
2.41.0


^ permalink raw reply related	[flat|nested] 50+ messages in thread

* [PATCH v2 08/37] powerpc/nohash: Remove {pte/pmd}_protnone()
  2023-09-25 18:31 [PATCH v2 00/37] Implement execute-only protection on powerpc Christophe Leroy
                   ` (6 preceding siblings ...)
  2023-09-25 18:31 ` [PATCH v2 07/37] powerpc: Untangle fixmap.h and pgtable.h and mmu.h Christophe Leroy
@ 2023-09-25 18:31 ` Christophe Leroy
  2023-09-25 18:31 ` [PATCH v2 09/37] powerpc/nohash: Refactor declaration of {map/unmap}_kernel_page() Christophe Leroy
                   ` (30 subsequent siblings)
  38 siblings, 0 replies; 50+ messages in thread
From: Christophe Leroy @ 2023-09-25 18:31 UTC (permalink / raw)
  To: Michael Ellerman, Nicholas Piggin; +Cc: linuxppc-dev, linux-kernel

Only book3s/64 selects ARCH_SUPPORTS_NUMA_BALANCING so
CONFIG_NUMA_BALANCING can't be selected on nohash targets.

Remove pte_protnone() and pmd_protnone().

Signed-off-by: Christophe Leroy <christophe.leroy@csgroup.eu>
---
 arch/powerpc/include/asm/nohash/pgtable.h | 17 -----------------
 1 file changed, 17 deletions(-)

diff --git a/arch/powerpc/include/asm/nohash/pgtable.h b/arch/powerpc/include/asm/nohash/pgtable.h
index a9056f4fad48..ab26af2b421a 100644
--- a/arch/powerpc/include/asm/nohash/pgtable.h
+++ b/arch/powerpc/include/asm/nohash/pgtable.h
@@ -35,23 +35,6 @@ static inline bool pte_hashpte(pte_t pte)	{ return false; }
 static inline bool pte_ci(pte_t pte)		{ return pte_val(pte) & _PAGE_NO_CACHE; }
 static inline bool pte_exec(pte_t pte)		{ return pte_val(pte) & _PAGE_EXEC; }
 
-#ifdef CONFIG_NUMA_BALANCING
-/*
- * These work without NUMA balancing but the kernel does not care. See the
- * comment in include/linux/pgtable.h . On powerpc, this will only
- * work for user pages and always return true for kernel pages.
- */
-static inline int pte_protnone(pte_t pte)
-{
-	return pte_present(pte) && !pte_user(pte);
-}
-
-static inline int pmd_protnone(pmd_t pmd)
-{
-	return pte_protnone(pmd_pte(pmd));
-}
-#endif /* CONFIG_NUMA_BALANCING */
-
 static inline int pte_present(pte_t pte)
 {
 	return pte_val(pte) & _PAGE_PRESENT;
-- 
2.41.0


^ permalink raw reply related	[flat|nested] 50+ messages in thread

* [PATCH v2 09/37] powerpc/nohash: Refactor declaration of {map/unmap}_kernel_page()
  2023-09-25 18:31 [PATCH v2 00/37] Implement execute-only protection on powerpc Christophe Leroy
                   ` (7 preceding siblings ...)
  2023-09-25 18:31 ` [PATCH v2 08/37] powerpc/nohash: Remove {pte/pmd}_protnone() Christophe Leroy
@ 2023-09-25 18:31 ` Christophe Leroy
  2023-09-25 18:31 ` [PATCH v2 10/37] powerpc/nohash: Move 8xx version of pte_update() into pte-8xx.h Christophe Leroy
                   ` (29 subsequent siblings)
  38 siblings, 0 replies; 50+ messages in thread
From: Christophe Leroy @ 2023-09-25 18:31 UTC (permalink / raw)
  To: Michael Ellerman, Nicholas Piggin; +Cc: linuxppc-dev, linux-kernel

map_kernel_page() and unmap_kernel_page() have the same prototypes
on nohash/32 and nohash/64, keep only one declaration.

Signed-off-by: Christophe Leroy <christophe.leroy@csgroup.eu>
---
 arch/powerpc/include/asm/nohash/32/pgtable.h | 8 --------
 arch/powerpc/include/asm/nohash/64/pgtable.h | 2 --
 arch/powerpc/include/asm/nohash/pgtable.h    | 3 +++
 arch/powerpc/mm/nohash/book3e_pgtable.c      | 2 +-
 4 files changed, 4 insertions(+), 11 deletions(-)

diff --git a/arch/powerpc/include/asm/nohash/32/pgtable.h b/arch/powerpc/include/asm/nohash/32/pgtable.h
index c8311ee08811..26289e4e767c 100644
--- a/arch/powerpc/include/asm/nohash/32/pgtable.h
+++ b/arch/powerpc/include/asm/nohash/32/pgtable.h
@@ -58,14 +58,6 @@ extern int icache_44x_need_flush;
 #define pgd_ERROR(e) \
 	pr_err("%s:%d: bad pgd %08lx.\n", __FILE__, __LINE__, pgd_val(e))
 
-#ifndef __ASSEMBLY__
-
-int map_kernel_page(unsigned long va, phys_addr_t pa, pgprot_t prot);
-void unmap_kernel_page(unsigned long va);
-
-#endif /* !__ASSEMBLY__ */
-
-
 /*
  * This is the bottom of the PKMAP area with HIGHMEM or an arbitrary
  * value (for now) on others, from where we can start layout kernel
diff --git a/arch/powerpc/include/asm/nohash/64/pgtable.h b/arch/powerpc/include/asm/nohash/64/pgtable.h
index dee3fc654d40..f5a8e8a9dba4 100644
--- a/arch/powerpc/include/asm/nohash/64/pgtable.h
+++ b/arch/powerpc/include/asm/nohash/64/pgtable.h
@@ -309,8 +309,6 @@ static inline void __ptep_set_access_flags(struct vm_area_struct *vma,
 /* We borrow MSB 56 (LSB 7) to store the exclusive marker in swap PTEs. */
 #define _PAGE_SWP_EXCLUSIVE	0x80
 
-int map_kernel_page(unsigned long ea, unsigned long pa, pgprot_t prot);
-void unmap_kernel_page(unsigned long va);
 extern int __meminit vmemmap_create_mapping(unsigned long start,
 					    unsigned long page_size,
 					    unsigned long phys);
diff --git a/arch/powerpc/include/asm/nohash/pgtable.h b/arch/powerpc/include/asm/nohash/pgtable.h
index ab26af2b421a..3d684b500fe6 100644
--- a/arch/powerpc/include/asm/nohash/pgtable.h
+++ b/arch/powerpc/include/asm/nohash/pgtable.h
@@ -242,5 +242,8 @@ static inline int pud_huge(pud_t pud)
 #define is_hugepd(hpd)		(hugepd_ok(hpd))
 #endif
 
+int map_kernel_page(unsigned long va, phys_addr_t pa, pgprot_t prot);
+void unmap_kernel_page(unsigned long va);
+
 #endif /* __ASSEMBLY__ */
 #endif
diff --git a/arch/powerpc/mm/nohash/book3e_pgtable.c b/arch/powerpc/mm/nohash/book3e_pgtable.c
index b80fc4a91a53..1c5e4ecbebeb 100644
--- a/arch/powerpc/mm/nohash/book3e_pgtable.c
+++ b/arch/powerpc/mm/nohash/book3e_pgtable.c
@@ -71,7 +71,7 @@ static void __init *early_alloc_pgtable(unsigned long size)
  * map_kernel_page adds an entry to the ioremap page table
  * and adds an entry to the HPT, possibly bolting it
  */
-int __ref map_kernel_page(unsigned long ea, unsigned long pa, pgprot_t prot)
+int __ref map_kernel_page(unsigned long ea, phys_addr_t pa, pgprot_t prot)
 {
 	pgd_t *pgdp;
 	p4d_t *p4dp;
-- 
2.41.0


^ permalink raw reply related	[flat|nested] 50+ messages in thread

* [PATCH v2 10/37] powerpc/nohash: Move 8xx version of pte_update() into pte-8xx.h
  2023-09-25 18:31 [PATCH v2 00/37] Implement execute-only protection on powerpc Christophe Leroy
                   ` (8 preceding siblings ...)
  2023-09-25 18:31 ` [PATCH v2 09/37] powerpc/nohash: Refactor declaration of {map/unmap}_kernel_page() Christophe Leroy
@ 2023-09-25 18:31 ` Christophe Leroy
  2023-09-25 18:31 ` [PATCH v2 11/37] powerpc/nohash: Replace #ifdef CONFIG_44x by IS_ENABLED(CONFIG_44x) in pgtable.h Christophe Leroy
                   ` (28 subsequent siblings)
  38 siblings, 0 replies; 50+ messages in thread
From: Christophe Leroy @ 2023-09-25 18:31 UTC (permalink / raw)
  To: Michael Ellerman, Nicholas Piggin; +Cc: linuxppc-dev, linux-kernel

No point in having 8xx special pte_update() in common header,
move it into pte-8xx.h

Signed-off-by: Christophe Leroy <christophe.leroy@csgroup.eu>
---
 arch/powerpc/include/asm/nohash/32/pgtable.h | 57 +-------------------
 arch/powerpc/include/asm/nohash/32/pte-8xx.h | 57 ++++++++++++++++++++
 2 files changed, 58 insertions(+), 56 deletions(-)

diff --git a/arch/powerpc/include/asm/nohash/32/pgtable.h b/arch/powerpc/include/asm/nohash/32/pgtable.h
index 26289e4e767c..be8bca42bdce 100644
--- a/arch/powerpc/include/asm/nohash/32/pgtable.h
+++ b/arch/powerpc/include/asm/nohash/32/pgtable.h
@@ -219,63 +219,8 @@ static inline void pmd_clear(pmd_t *pmdp)
  * that an executable user mapping was modified, which is needed
  * to properly flush the virtually tagged instruction cache of
  * those implementations.
- *
- * On the 8xx, the page tables are a bit special. For 16k pages, we have
- * 4 identical entries. For 512k pages, we have 128 entries as if it was
- * 4k pages, but they are flagged as 512k pages for the hardware.
- * For other page sizes, we have a single entry in the table.
  */
-#ifdef CONFIG_PPC_8xx
-static pmd_t *pmd_off(struct mm_struct *mm, unsigned long addr);
-static int hugepd_ok(hugepd_t hpd);
-
-static int number_of_cells_per_pte(pmd_t *pmd, pte_basic_t val, int huge)
-{
-	if (!huge)
-		return PAGE_SIZE / SZ_4K;
-	else if (hugepd_ok(*((hugepd_t *)pmd)))
-		return 1;
-	else if (IS_ENABLED(CONFIG_PPC_4K_PAGES) && !(val & _PAGE_HUGE))
-		return SZ_16K / SZ_4K;
-	else
-		return SZ_512K / SZ_4K;
-}
-
-static inline pte_basic_t pte_update(struct mm_struct *mm, unsigned long addr, pte_t *p,
-				     unsigned long clr, unsigned long set, int huge)
-{
-	pte_basic_t *entry = (pte_basic_t *)p;
-	pte_basic_t old = pte_val(*p);
-	pte_basic_t new = (old & ~(pte_basic_t)clr) | set;
-	int num, i;
-	pmd_t *pmd = pmd_off(mm, addr);
-
-	num = number_of_cells_per_pte(pmd, new, huge);
-
-	for (i = 0; i < num; i += PAGE_SIZE / SZ_4K, new += PAGE_SIZE) {
-		*entry++ = new;
-		if (IS_ENABLED(CONFIG_PPC_16K_PAGES) && num != 1) {
-			*entry++ = new;
-			*entry++ = new;
-			*entry++ = new;
-		}
-	}
-
-	return old;
-}
-
-#ifdef CONFIG_PPC_16K_PAGES
-#define ptep_get ptep_get
-static inline pte_t ptep_get(pte_t *ptep)
-{
-	pte_basic_t val = READ_ONCE(ptep->pte);
-	pte_t pte = {val, val, val, val};
-
-	return pte;
-}
-#endif /* CONFIG_PPC_16K_PAGES */
-
-#else
+#ifndef pte_update
 static inline pte_basic_t pte_update(struct mm_struct *mm, unsigned long addr, pte_t *p,
 				     unsigned long clr, unsigned long set, int huge)
 {
diff --git a/arch/powerpc/include/asm/nohash/32/pte-8xx.h b/arch/powerpc/include/asm/nohash/32/pte-8xx.h
index e6fe1d5731f2..52395a5ecd70 100644
--- a/arch/powerpc/include/asm/nohash/32/pte-8xx.h
+++ b/arch/powerpc/include/asm/nohash/32/pte-8xx.h
@@ -187,6 +187,63 @@ static inline unsigned long pte_leaf_size(pte_t pte)
 
 #define pte_leaf_size pte_leaf_size
 
+/*
+ * On the 8xx, the page tables are a bit special. For 16k pages, we have
+ * 4 identical entries. For 512k pages, we have 128 entries as if it was
+ * 4k pages, but they are flagged as 512k pages for the hardware.
+ * For other page sizes, we have a single entry in the table.
+ */
+static pmd_t *pmd_off(struct mm_struct *mm, unsigned long addr);
+static int hugepd_ok(hugepd_t hpd);
+
+static inline int number_of_cells_per_pte(pmd_t *pmd, pte_basic_t val, int huge)
+{
+	if (!huge)
+		return PAGE_SIZE / SZ_4K;
+	else if (hugepd_ok(*((hugepd_t *)pmd)))
+		return 1;
+	else if (IS_ENABLED(CONFIG_PPC_4K_PAGES) && !(val & _PAGE_HUGE))
+		return SZ_16K / SZ_4K;
+	else
+		return SZ_512K / SZ_4K;
+}
+
+static inline pte_basic_t pte_update(struct mm_struct *mm, unsigned long addr, pte_t *p,
+				     unsigned long clr, unsigned long set, int huge)
+{
+	pte_basic_t *entry = (pte_basic_t *)p;
+	pte_basic_t old = pte_val(*p);
+	pte_basic_t new = (old & ~(pte_basic_t)clr) | set;
+	int num, i;
+	pmd_t *pmd = pmd_off(mm, addr);
+
+	num = number_of_cells_per_pte(pmd, new, huge);
+
+	for (i = 0; i < num; i += PAGE_SIZE / SZ_4K, new += PAGE_SIZE) {
+		*entry++ = new;
+		if (IS_ENABLED(CONFIG_PPC_16K_PAGES) && num != 1) {
+			*entry++ = new;
+			*entry++ = new;
+			*entry++ = new;
+		}
+	}
+
+	return old;
+}
+
+#define pte_update pte_update
+
+#ifdef CONFIG_PPC_16K_PAGES
+#define ptep_get ptep_get
+static inline pte_t ptep_get(pte_t *ptep)
+{
+	pte_basic_t val = READ_ONCE(ptep->pte);
+	pte_t pte = {val, val, val, val};
+
+	return pte;
+}
+#endif /* CONFIG_PPC_16K_PAGES */
+
 #endif
 
 #endif /* __KERNEL__ */
-- 
2.41.0


^ permalink raw reply related	[flat|nested] 50+ messages in thread

* [PATCH v2 11/37] powerpc/nohash: Replace #ifdef CONFIG_44x by IS_ENABLED(CONFIG_44x) in pgtable.h
  2023-09-25 18:31 [PATCH v2 00/37] Implement execute-only protection on powerpc Christophe Leroy
                   ` (9 preceding siblings ...)
  2023-09-25 18:31 ` [PATCH v2 10/37] powerpc/nohash: Move 8xx version of pte_update() into pte-8xx.h Christophe Leroy
@ 2023-09-25 18:31 ` Christophe Leroy
  2023-09-25 18:31 ` [PATCH v2 12/37] powerpc/nohash: Refactor pte_update() Christophe Leroy
                   ` (27 subsequent siblings)
  38 siblings, 0 replies; 50+ messages in thread
From: Christophe Leroy @ 2023-09-25 18:31 UTC (permalink / raw)
  To: Michael Ellerman, Nicholas Piggin; +Cc: linuxppc-dev, linux-kernel

No need of a #ifdef, use IS_ENABLED(CONFIG_44x)

Signed-off-by: Christophe Leroy <christophe.leroy@csgroup.eu>
---
 arch/powerpc/include/asm/nohash/32/pgtable.h | 7 ++-----
 1 file changed, 2 insertions(+), 5 deletions(-)

diff --git a/arch/powerpc/include/asm/nohash/32/pgtable.h b/arch/powerpc/include/asm/nohash/32/pgtable.h
index be8bca42bdce..a74476de1ef6 100644
--- a/arch/powerpc/include/asm/nohash/32/pgtable.h
+++ b/arch/powerpc/include/asm/nohash/32/pgtable.h
@@ -9,9 +9,7 @@
 #include <linux/threads.h>
 #include <asm/mmu.h>			/* For sub-arch specific PPC_PIN_SIZE */
 
-#ifdef CONFIG_44x
 extern int icache_44x_need_flush;
-#endif
 
 #endif /* __ASSEMBLY__ */
 
@@ -229,10 +227,9 @@ static inline pte_basic_t pte_update(struct mm_struct *mm, unsigned long addr, p
 
 	*p = __pte(new);
 
-#ifdef CONFIG_44x
-	if ((old & _PAGE_USER) && (old & _PAGE_EXEC))
+	if (IS_ENABLED(CONFIG_44x) && (old & _PAGE_USER) && (old & _PAGE_EXEC))
 		icache_44x_need_flush = 1;
-#endif
+
 	return old;
 }
 #endif
-- 
2.41.0


^ permalink raw reply related	[flat|nested] 50+ messages in thread

* [PATCH v2 12/37] powerpc/nohash: Refactor pte_update()
  2023-09-25 18:31 [PATCH v2 00/37] Implement execute-only protection on powerpc Christophe Leroy
                   ` (10 preceding siblings ...)
  2023-09-25 18:31 ` [PATCH v2 11/37] powerpc/nohash: Replace #ifdef CONFIG_44x by IS_ENABLED(CONFIG_44x) in pgtable.h Christophe Leroy
@ 2023-09-25 18:31 ` Christophe Leroy
  2023-09-25 18:31 ` [PATCH v2 13/37] powerpc/nohash: Refactor checking of no-change in pte_update() Christophe Leroy
                   ` (26 subsequent siblings)
  38 siblings, 0 replies; 50+ messages in thread
From: Christophe Leroy @ 2023-09-25 18:31 UTC (permalink / raw)
  To: Michael Ellerman, Nicholas Piggin; +Cc: linuxppc-dev, linux-kernel

pte_update() is similar.

Take the nohash/32 version which works on nohash/64 and add the debug
call to assert_pte_locked() which is only on nohash/64.

Signed-off-by: Christophe Leroy <christophe.leroy@csgroup.eu>
---
 arch/powerpc/include/asm/nohash/32/pgtable.h | 33 ---------------
 arch/powerpc/include/asm/nohash/64/pgtable.h | 17 --------
 arch/powerpc/include/asm/nohash/pgtable.h    | 42 ++++++++++++++++++++
 3 files changed, 42 insertions(+), 50 deletions(-)

diff --git a/arch/powerpc/include/asm/nohash/32/pgtable.h b/arch/powerpc/include/asm/nohash/32/pgtable.h
index a74476de1ef6..ae7f3c8afd4f 100644
--- a/arch/powerpc/include/asm/nohash/32/pgtable.h
+++ b/arch/powerpc/include/asm/nohash/32/pgtable.h
@@ -9,8 +9,6 @@
 #include <linux/threads.h>
 #include <asm/mmu.h>			/* For sub-arch specific PPC_PIN_SIZE */
 
-extern int icache_44x_need_flush;
-
 #endif /* __ASSEMBLY__ */
 
 #define PTE_INDEX_SIZE	PTE_SHIFT
@@ -203,37 +201,6 @@ static inline void pmd_clear(pmd_t *pmdp)
 	*pmdp = __pmd(0);
 }
 
-/*
- * PTE updates. This function is called whenever an existing
- * valid PTE is updated. This does -not- include set_pte_at()
- * which nowadays only sets a new PTE.
- *
- * Depending on the type of MMU, we may need to use atomic updates
- * and the PTE may be either 32 or 64 bit wide. In the later case,
- * when using atomic updates, only the low part of the PTE is
- * accessed atomically.
- *
- * In addition, on 44x, we also maintain a global flag indicating
- * that an executable user mapping was modified, which is needed
- * to properly flush the virtually tagged instruction cache of
- * those implementations.
- */
-#ifndef pte_update
-static inline pte_basic_t pte_update(struct mm_struct *mm, unsigned long addr, pte_t *p,
-				     unsigned long clr, unsigned long set, int huge)
-{
-	pte_basic_t old = pte_val(*p);
-	pte_basic_t new = (old & ~(pte_basic_t)clr) | set;
-
-	*p = __pte(new);
-
-	if (IS_ENABLED(CONFIG_44x) && (old & _PAGE_USER) && (old & _PAGE_EXEC))
-		icache_44x_need_flush = 1;
-
-	return old;
-}
-#endif
-
 #define __HAVE_ARCH_PTEP_TEST_AND_CLEAR_YOUNG
 static inline int __ptep_test_and_clear_young(struct mm_struct *mm,
 					      unsigned long addr, pte_t *ptep)
diff --git a/arch/powerpc/include/asm/nohash/64/pgtable.h b/arch/powerpc/include/asm/nohash/64/pgtable.h
index f5a8e8a9dba4..b149a39f2685 100644
--- a/arch/powerpc/include/asm/nohash/64/pgtable.h
+++ b/arch/powerpc/include/asm/nohash/64/pgtable.h
@@ -171,23 +171,6 @@ static inline void p4d_set(p4d_t *p4dp, unsigned long val)
 	*p4dp = __p4d(val);
 }
 
-/* Atomic PTE updates */
-static inline unsigned long pte_update(struct mm_struct *mm,
-				       unsigned long addr,
-				       pte_t *ptep, unsigned long clr,
-				       unsigned long set,
-				       int huge)
-{
-	unsigned long old = pte_val(*ptep);
-	*ptep = __pte((old & ~clr) | set);
-
-	/* huge pages use the old page table lock */
-	if (!huge)
-		assert_pte_locked(mm, addr);
-
-	return old;
-}
-
 static inline int pte_young(pte_t pte)
 {
 	return pte_val(pte) & _PAGE_ACCESSED;
diff --git a/arch/powerpc/include/asm/nohash/pgtable.h b/arch/powerpc/include/asm/nohash/pgtable.h
index 3d684b500fe6..bd5c3a4baabd 100644
--- a/arch/powerpc/include/asm/nohash/pgtable.h
+++ b/arch/powerpc/include/asm/nohash/pgtable.h
@@ -2,6 +2,11 @@
 #ifndef _ASM_POWERPC_NOHASH_PGTABLE_H
 #define _ASM_POWERPC_NOHASH_PGTABLE_H
 
+#ifndef __ASSEMBLY__
+static inline pte_basic_t pte_update(struct mm_struct *mm, unsigned long addr, pte_t *p,
+				     unsigned long clr, unsigned long set, int huge);
+#endif
+
 #if defined(CONFIG_PPC64)
 #include <asm/nohash/64/pgtable.h>
 #else
@@ -18,6 +23,43 @@
 
 #ifndef __ASSEMBLY__
 
+extern int icache_44x_need_flush;
+
+/*
+ * PTE updates. This function is called whenever an existing
+ * valid PTE is updated. This does -not- include set_pte_at()
+ * which nowadays only sets a new PTE.
+ *
+ * Depending on the type of MMU, we may need to use atomic updates
+ * and the PTE may be either 32 or 64 bit wide. In the later case,
+ * when using atomic updates, only the low part of the PTE is
+ * accessed atomically.
+ *
+ * In addition, on 44x, we also maintain a global flag indicating
+ * that an executable user mapping was modified, which is needed
+ * to properly flush the virtually tagged instruction cache of
+ * those implementations.
+ */
+#ifndef pte_update
+static inline pte_basic_t pte_update(struct mm_struct *mm, unsigned long addr, pte_t *p,
+				     unsigned long clr, unsigned long set, int huge)
+{
+	pte_basic_t old = pte_val(*p);
+	pte_basic_t new = (old & ~(pte_basic_t)clr) | set;
+
+	*p = __pte(new);
+
+	if (IS_ENABLED(CONFIG_44x) && (old & _PAGE_USER) && (old & _PAGE_EXEC))
+		icache_44x_need_flush = 1;
+
+	/* huge pages use the old page table lock */
+	if (!huge)
+		assert_pte_locked(mm, addr);
+
+	return old;
+}
+#endif
+
 /* Generic accessors to PTE bits */
 #ifndef pte_write
 static inline int pte_write(pte_t pte)
-- 
2.41.0


^ permalink raw reply related	[flat|nested] 50+ messages in thread

* [PATCH v2 13/37] powerpc/nohash: Refactor checking of no-change in pte_update()
  2023-09-25 18:31 [PATCH v2 00/37] Implement execute-only protection on powerpc Christophe Leroy
                   ` (11 preceding siblings ...)
  2023-09-25 18:31 ` [PATCH v2 12/37] powerpc/nohash: Refactor pte_update() Christophe Leroy
@ 2023-09-25 18:31 ` Christophe Leroy
  2023-09-25 18:31 ` [PATCH v2 14/37] powerpc/nohash: Deduplicate _PAGE_CHG_MASK Christophe Leroy
                   ` (25 subsequent siblings)
  38 siblings, 0 replies; 50+ messages in thread
From: Christophe Leroy @ 2023-09-25 18:31 UTC (permalink / raw)
  To: Michael Ellerman, Nicholas Piggin; +Cc: linuxppc-dev, linux-kernel

On nohash/64, a few callers of pte_update() check if there is
really a change in order to avoid an unnecessary write.

Refactor that inside pte_update().

Signed-off-by: Christophe Leroy <christophe.leroy@csgroup.eu>
---
 arch/powerpc/include/asm/nohash/64/pgtable.h | 9 ---------
 arch/powerpc/include/asm/nohash/pgtable.h    | 3 +++
 2 files changed, 3 insertions(+), 9 deletions(-)

diff --git a/arch/powerpc/include/asm/nohash/64/pgtable.h b/arch/powerpc/include/asm/nohash/64/pgtable.h
index b149a39f2685..cba08a62c52c 100644
--- a/arch/powerpc/include/asm/nohash/64/pgtable.h
+++ b/arch/powerpc/include/asm/nohash/64/pgtable.h
@@ -181,8 +181,6 @@ static inline int __ptep_test_and_clear_young(struct mm_struct *mm,
 {
 	unsigned long old;
 
-	if (!pte_young(*ptep))
-		return 0;
 	old = pte_update(mm, addr, ptep, _PAGE_ACCESSED, 0, 0);
 	return (old & _PAGE_ACCESSED) != 0;
 }
@@ -198,10 +196,6 @@ static inline int __ptep_test_and_clear_young(struct mm_struct *mm,
 static inline void ptep_set_wrprotect(struct mm_struct *mm, unsigned long addr,
 				      pte_t *ptep)
 {
-
-	if ((pte_val(*ptep) & _PAGE_RW) == 0)
-		return;
-
 	pte_update(mm, addr, ptep, _PAGE_RW, 0, 0);
 }
 
@@ -209,9 +203,6 @@ static inline void ptep_set_wrprotect(struct mm_struct *mm, unsigned long addr,
 static inline void huge_ptep_set_wrprotect(struct mm_struct *mm,
 					   unsigned long addr, pte_t *ptep)
 {
-	if ((pte_val(*ptep) & _PAGE_RW) == 0)
-		return;
-
 	pte_update(mm, addr, ptep, _PAGE_RW, 0, 1);
 }
 
diff --git a/arch/powerpc/include/asm/nohash/pgtable.h b/arch/powerpc/include/asm/nohash/pgtable.h
index bd5c3a4baabd..8adaacbbdd1d 100644
--- a/arch/powerpc/include/asm/nohash/pgtable.h
+++ b/arch/powerpc/include/asm/nohash/pgtable.h
@@ -47,6 +47,9 @@ static inline pte_basic_t pte_update(struct mm_struct *mm, unsigned long addr, p
 	pte_basic_t old = pte_val(*p);
 	pte_basic_t new = (old & ~(pte_basic_t)clr) | set;
 
+	if (new == old)
+		return old;
+
 	*p = __pte(new);
 
 	if (IS_ENABLED(CONFIG_44x) && (old & _PAGE_USER) && (old & _PAGE_EXEC))
-- 
2.41.0


^ permalink raw reply related	[flat|nested] 50+ messages in thread

* [PATCH v2 14/37] powerpc/nohash: Deduplicate _PAGE_CHG_MASK
  2023-09-25 18:31 [PATCH v2 00/37] Implement execute-only protection on powerpc Christophe Leroy
                   ` (12 preceding siblings ...)
  2023-09-25 18:31 ` [PATCH v2 13/37] powerpc/nohash: Refactor checking of no-change in pte_update() Christophe Leroy
@ 2023-09-25 18:31 ` Christophe Leroy
  2023-09-25 18:31 ` [PATCH v2 15/37] powerpc/nohash: Deduplicate pte helpers Christophe Leroy
                   ` (24 subsequent siblings)
  38 siblings, 0 replies; 50+ messages in thread
From: Christophe Leroy @ 2023-09-25 18:31 UTC (permalink / raw)
  To: Michael Ellerman, Nicholas Piggin; +Cc: linuxppc-dev, linux-kernel

_PAGE_CHG_MASK is identical between nohash/32 and nohash/64,
deduplicate it.

While at it, clean the #ifdef for PTE_RPN_MASK in nohash/32 as
it is already CONFIG_PPC32.

Signed-off-by: Christophe Leroy <christophe.leroy@csgroup.eu>
---
 arch/powerpc/include/asm/nohash/32/pgtable.h | 8 +-------
 arch/powerpc/include/asm/nohash/64/pgtable.h | 6 ------
 arch/powerpc/include/asm/nohash/pgtable.h    | 6 ++++++
 3 files changed, 7 insertions(+), 13 deletions(-)

diff --git a/arch/powerpc/include/asm/nohash/32/pgtable.h b/arch/powerpc/include/asm/nohash/32/pgtable.h
index ae7f3c8afd4f..a39ecd498084 100644
--- a/arch/powerpc/include/asm/nohash/32/pgtable.h
+++ b/arch/powerpc/include/asm/nohash/32/pgtable.h
@@ -143,7 +143,7 @@
  * The mask covered by the RPN must be a ULL on 32-bit platforms with
  * 64-bit PTEs.
  */
-#if defined(CONFIG_PPC32) && defined(CONFIG_PTE_64BIT)
+#ifdef CONFIG_PTE_64BIT
 #define PTE_RPN_MASK	(~((1ULL << PTE_RPN_SHIFT) - 1))
 #define MAX_POSSIBLE_PHYSMEM_BITS 36
 #else
@@ -151,12 +151,6 @@
 #define MAX_POSSIBLE_PHYSMEM_BITS 32
 #endif
 
-/*
- * _PAGE_CHG_MASK masks of bits that are to be preserved across
- * pgprot changes.
- */
-#define _PAGE_CHG_MASK	(PTE_RPN_MASK | _PAGE_DIRTY | _PAGE_ACCESSED | _PAGE_SPECIAL)
-
 #ifndef __ASSEMBLY__
 
 #define pte_clear(mm, addr, ptep) \
diff --git a/arch/powerpc/include/asm/nohash/64/pgtable.h b/arch/powerpc/include/asm/nohash/64/pgtable.h
index cba08a62c52c..34a518a1c04d 100644
--- a/arch/powerpc/include/asm/nohash/64/pgtable.h
+++ b/arch/powerpc/include/asm/nohash/64/pgtable.h
@@ -75,12 +75,6 @@
 
 #define PTE_RPN_MASK	(~((1UL << PTE_RPN_SHIFT) - 1))
 
-/*
- * _PAGE_CHG_MASK masks of bits that are to be preserved across
- * pgprot changes.
- */
-#define _PAGE_CHG_MASK	(PTE_RPN_MASK | _PAGE_DIRTY | _PAGE_ACCESSED | _PAGE_SPECIAL)
-
 #define H_PAGE_4K_PFN 0
 
 #ifndef __ASSEMBLY__
diff --git a/arch/powerpc/include/asm/nohash/pgtable.h b/arch/powerpc/include/asm/nohash/pgtable.h
index 8adaacbbdd1d..c64a040f4a6a 100644
--- a/arch/powerpc/include/asm/nohash/pgtable.h
+++ b/arch/powerpc/include/asm/nohash/pgtable.h
@@ -13,6 +13,12 @@ static inline pte_basic_t pte_update(struct mm_struct *mm, unsigned long addr, p
 #include <asm/nohash/32/pgtable.h>
 #endif
 
+/*
+ * _PAGE_CHG_MASK masks of bits that are to be preserved across
+ * pgprot changes.
+ */
+#define _PAGE_CHG_MASK	(PTE_RPN_MASK | _PAGE_DIRTY | _PAGE_ACCESSED | _PAGE_SPECIAL)
+
 /* Permission masks used for kernel mappings */
 #define PAGE_KERNEL	__pgprot(_PAGE_BASE | _PAGE_KERNEL_RW)
 #define PAGE_KERNEL_NC	__pgprot(_PAGE_BASE_NC | _PAGE_KERNEL_RW | _PAGE_NO_CACHE)
-- 
2.41.0


^ permalink raw reply related	[flat|nested] 50+ messages in thread

* [PATCH v2 15/37] powerpc/nohash: Deduplicate pte helpers
  2023-09-25 18:31 [PATCH v2 00/37] Implement execute-only protection on powerpc Christophe Leroy
                   ` (13 preceding siblings ...)
  2023-09-25 18:31 ` [PATCH v2 14/37] powerpc/nohash: Deduplicate _PAGE_CHG_MASK Christophe Leroy
@ 2023-09-25 18:31 ` Christophe Leroy
  2023-09-25 18:31 ` [PATCH v2 16/37] powerpc/nohash: Refactor ptep_test_and_clear_young() Christophe Leroy
                   ` (23 subsequent siblings)
  38 siblings, 0 replies; 50+ messages in thread
From: Christophe Leroy @ 2023-09-25 18:31 UTC (permalink / raw)
  To: Michael Ellerman, Nicholas Piggin; +Cc: linuxppc-dev, linux-kernel

Deduplicate following helpers that are identical on
nohash/32 and nohash/64:
  pte_mkwrite_novma()
  pte_mkdirty()
  pte_mkyoung()
  pte_wrprotect()
  pte_mkexec()
  pte_young()

Signed-off-by: Christophe Leroy <christophe.leroy@csgroup.eu>
---
 arch/powerpc/include/asm/nohash/32/pgtable.h | 36 --------------------
 arch/powerpc/include/asm/nohash/64/pgtable.h | 25 --------------
 arch/powerpc/include/asm/nohash/pgtable.h    | 36 ++++++++++++++++++++
 3 files changed, 36 insertions(+), 61 deletions(-)

diff --git a/arch/powerpc/include/asm/nohash/32/pgtable.h b/arch/powerpc/include/asm/nohash/32/pgtable.h
index a39ecd498084..de51f78449a0 100644
--- a/arch/powerpc/include/asm/nohash/32/pgtable.h
+++ b/arch/powerpc/include/asm/nohash/32/pgtable.h
@@ -156,37 +156,6 @@
 #define pte_clear(mm, addr, ptep) \
 	do { pte_update(mm, addr, ptep, ~0, 0, 0); } while (0)
 
-#ifndef pte_mkwrite_novma
-static inline pte_t pte_mkwrite_novma(pte_t pte)
-{
-	return __pte(pte_val(pte) | _PAGE_RW);
-}
-#endif
-
-static inline pte_t pte_mkdirty(pte_t pte)
-{
-	return __pte(pte_val(pte) | _PAGE_DIRTY);
-}
-
-static inline pte_t pte_mkyoung(pte_t pte)
-{
-	return __pte(pte_val(pte) | _PAGE_ACCESSED);
-}
-
-#ifndef pte_wrprotect
-static inline pte_t pte_wrprotect(pte_t pte)
-{
-	return __pte(pte_val(pte) & ~_PAGE_RW);
-}
-#endif
-
-#ifndef pte_mkexec
-static inline pte_t pte_mkexec(pte_t pte)
-{
-	return __pte(pte_val(pte) | _PAGE_EXEC);
-}
-#endif
-
 #define pmd_none(pmd)		(!pmd_val(pmd))
 #define	pmd_bad(pmd)		(pmd_val(pmd) & _PMD_BAD)
 #define	pmd_present(pmd)	(pmd_val(pmd) & _PMD_PRESENT_MASK)
@@ -238,11 +207,6 @@ static inline void __ptep_set_access_flags(struct vm_area_struct *vma,
 }
 #endif
 
-static inline int pte_young(pte_t pte)
-{
-	return pte_val(pte) & _PAGE_ACCESSED;
-}
-
 /*
  * Note that on Book E processors, the pmd contains the kernel virtual
  * (lowmem) address of the pte page.  The physical address is less useful
diff --git a/arch/powerpc/include/asm/nohash/64/pgtable.h b/arch/powerpc/include/asm/nohash/64/pgtable.h
index 34a518a1c04d..e8bbc6ec1084 100644
--- a/arch/powerpc/include/asm/nohash/64/pgtable.h
+++ b/arch/powerpc/include/asm/nohash/64/pgtable.h
@@ -80,26 +80,6 @@
 #ifndef __ASSEMBLY__
 /* pte_clear moved to later in this file */
 
-static inline pte_t pte_mkwrite_novma(pte_t pte)
-{
-	return __pte(pte_val(pte) | _PAGE_RW);
-}
-
-static inline pte_t pte_mkdirty(pte_t pte)
-{
-	return __pte(pte_val(pte) | _PAGE_DIRTY);
-}
-
-static inline pte_t pte_mkyoung(pte_t pte)
-{
-	return __pte(pte_val(pte) | _PAGE_ACCESSED);
-}
-
-static inline pte_t pte_wrprotect(pte_t pte)
-{
-	return __pte(pte_val(pte) & ~_PAGE_RW);
-}
-
 #define PMD_BAD_BITS		(PTE_TABLE_SIZE-1)
 #define PUD_BAD_BITS		(PMD_TABLE_SIZE-1)
 
@@ -165,11 +145,6 @@ static inline void p4d_set(p4d_t *p4dp, unsigned long val)
 	*p4dp = __p4d(val);
 }
 
-static inline int pte_young(pte_t pte)
-{
-	return pte_val(pte) & _PAGE_ACCESSED;
-}
-
 static inline int __ptep_test_and_clear_young(struct mm_struct *mm,
 					      unsigned long addr, pte_t *ptep)
 {
diff --git a/arch/powerpc/include/asm/nohash/pgtable.h b/arch/powerpc/include/asm/nohash/pgtable.h
index c64a040f4a6a..21f232d2e34f 100644
--- a/arch/powerpc/include/asm/nohash/pgtable.h
+++ b/arch/powerpc/include/asm/nohash/pgtable.h
@@ -70,6 +70,37 @@ static inline pte_basic_t pte_update(struct mm_struct *mm, unsigned long addr, p
 #endif
 
 /* Generic accessors to PTE bits */
+#ifndef pte_mkwrite_novma
+static inline pte_t pte_mkwrite_novma(pte_t pte)
+{
+	return __pte(pte_val(pte) | _PAGE_RW);
+}
+#endif
+
+static inline pte_t pte_mkdirty(pte_t pte)
+{
+	return __pte(pte_val(pte) | _PAGE_DIRTY);
+}
+
+static inline pte_t pte_mkyoung(pte_t pte)
+{
+	return __pte(pte_val(pte) | _PAGE_ACCESSED);
+}
+
+#ifndef pte_wrprotect
+static inline pte_t pte_wrprotect(pte_t pte)
+{
+	return __pte(pte_val(pte) & ~_PAGE_RW);
+}
+#endif
+
+#ifndef pte_mkexec
+static inline pte_t pte_mkexec(pte_t pte)
+{
+	return __pte(pte_val(pte) | _PAGE_EXEC);
+}
+#endif
+
 #ifndef pte_write
 static inline int pte_write(pte_t pte)
 {
@@ -96,6 +127,11 @@ static inline bool pte_hw_valid(pte_t pte)
 	return pte_val(pte) & _PAGE_PRESENT;
 }
 
+static inline int pte_young(pte_t pte)
+{
+	return pte_val(pte) & _PAGE_ACCESSED;
+}
+
 /*
  * Don't just check for any non zero bits in __PAGE_USER, since for book3e
  * and PTE_64BIT, PAGE_KERNEL_X contains _PAGE_BAP_SR which is also in
-- 
2.41.0


^ permalink raw reply related	[flat|nested] 50+ messages in thread

* [PATCH v2 16/37] powerpc/nohash: Refactor ptep_test_and_clear_young()
  2023-09-25 18:31 [PATCH v2 00/37] Implement execute-only protection on powerpc Christophe Leroy
                   ` (14 preceding siblings ...)
  2023-09-25 18:31 ` [PATCH v2 15/37] powerpc/nohash: Deduplicate pte helpers Christophe Leroy
@ 2023-09-25 18:31 ` Christophe Leroy
  2023-09-25 18:31 ` [PATCH v2 17/37] powerpc/nohash: Deduplicate ptep_set_wrprotect() and ptep_get_and_clear() Christophe Leroy
                   ` (22 subsequent siblings)
  38 siblings, 0 replies; 50+ messages in thread
From: Christophe Leroy @ 2023-09-25 18:31 UTC (permalink / raw)
  To: Michael Ellerman, Nicholas Piggin; +Cc: linuxppc-dev, linux-kernel

Remove ptep_test_and_clear_young() macro, make
__ptep_test_and_clear_young() common to nohash/32 and nohash/64
and change it to become ptep_test_and_clear_young()

Signed-off-by: Christophe Leroy <christophe.leroy@csgroup.eu>
---
 arch/powerpc/include/asm/nohash/32/pgtable.h | 11 -----------
 arch/powerpc/include/asm/nohash/64/pgtable.h | 19 +------------------
 arch/powerpc/include/asm/nohash/pgtable.h    | 11 +++++++++++
 3 files changed, 12 insertions(+), 29 deletions(-)

diff --git a/arch/powerpc/include/asm/nohash/32/pgtable.h b/arch/powerpc/include/asm/nohash/32/pgtable.h
index de51f78449a0..b7605000bd91 100644
--- a/arch/powerpc/include/asm/nohash/32/pgtable.h
+++ b/arch/powerpc/include/asm/nohash/32/pgtable.h
@@ -164,17 +164,6 @@ static inline void pmd_clear(pmd_t *pmdp)
 	*pmdp = __pmd(0);
 }
 
-#define __HAVE_ARCH_PTEP_TEST_AND_CLEAR_YOUNG
-static inline int __ptep_test_and_clear_young(struct mm_struct *mm,
-					      unsigned long addr, pte_t *ptep)
-{
-	unsigned long old;
-	old = pte_update(mm, addr, ptep, _PAGE_ACCESSED, 0, 0);
-	return (old & _PAGE_ACCESSED) != 0;
-}
-#define ptep_test_and_clear_young(__vma, __addr, __ptep) \
-	__ptep_test_and_clear_young((__vma)->vm_mm, __addr, __ptep)
-
 #define __HAVE_ARCH_PTEP_GET_AND_CLEAR
 static inline pte_t ptep_get_and_clear(struct mm_struct *mm, unsigned long addr,
 				       pte_t *ptep)
diff --git a/arch/powerpc/include/asm/nohash/64/pgtable.h b/arch/powerpc/include/asm/nohash/64/pgtable.h
index e8bbc6ec1084..56041036fa34 100644
--- a/arch/powerpc/include/asm/nohash/64/pgtable.h
+++ b/arch/powerpc/include/asm/nohash/64/pgtable.h
@@ -145,22 +145,6 @@ static inline void p4d_set(p4d_t *p4dp, unsigned long val)
 	*p4dp = __p4d(val);
 }
 
-static inline int __ptep_test_and_clear_young(struct mm_struct *mm,
-					      unsigned long addr, pte_t *ptep)
-{
-	unsigned long old;
-
-	old = pte_update(mm, addr, ptep, _PAGE_ACCESSED, 0, 0);
-	return (old & _PAGE_ACCESSED) != 0;
-}
-#define __HAVE_ARCH_PTEP_TEST_AND_CLEAR_YOUNG
-#define ptep_test_and_clear_young(__vma, __addr, __ptep)		   \
-({									   \
-	int __r;							   \
-	__r = __ptep_test_and_clear_young((__vma)->vm_mm, __addr, __ptep); \
-	__r;								   \
-})
-
 #define __HAVE_ARCH_PTEP_SET_WRPROTECT
 static inline void ptep_set_wrprotect(struct mm_struct *mm, unsigned long addr,
 				      pte_t *ptep)
@@ -178,8 +162,7 @@ static inline void huge_ptep_set_wrprotect(struct mm_struct *mm,
 #define __HAVE_ARCH_PTEP_CLEAR_YOUNG_FLUSH
 #define ptep_clear_flush_young(__vma, __address, __ptep)		\
 ({									\
-	int __young = __ptep_test_and_clear_young((__vma)->vm_mm, __address, \
-						  __ptep);		\
+	int __young = ptep_test_and_clear_young(__vma, __address, __ptep);\
 	__young;							\
 })
 
diff --git a/arch/powerpc/include/asm/nohash/pgtable.h b/arch/powerpc/include/asm/nohash/pgtable.h
index 21f232d2e34f..2b043b72f642 100644
--- a/arch/powerpc/include/asm/nohash/pgtable.h
+++ b/arch/powerpc/include/asm/nohash/pgtable.h
@@ -69,6 +69,17 @@ static inline pte_basic_t pte_update(struct mm_struct *mm, unsigned long addr, p
 }
 #endif
 
+static inline int ptep_test_and_clear_young(struct vm_area_struct *vma,
+					    unsigned long addr, pte_t *ptep)
+{
+	unsigned long old;
+
+	old = pte_update(vma->vm_mm, addr, ptep, _PAGE_ACCESSED, 0, 0);
+
+	return (old & _PAGE_ACCESSED) != 0;
+}
+#define __HAVE_ARCH_PTEP_TEST_AND_CLEAR_YOUNG
+
 /* Generic accessors to PTE bits */
 #ifndef pte_mkwrite_novma
 static inline pte_t pte_mkwrite_novma(pte_t pte)
-- 
2.41.0


^ permalink raw reply related	[flat|nested] 50+ messages in thread

* [PATCH v2 17/37] powerpc/nohash: Deduplicate ptep_set_wrprotect() and ptep_get_and_clear()
  2023-09-25 18:31 [PATCH v2 00/37] Implement execute-only protection on powerpc Christophe Leroy
                   ` (15 preceding siblings ...)
  2023-09-25 18:31 ` [PATCH v2 16/37] powerpc/nohash: Refactor ptep_test_and_clear_young() Christophe Leroy
@ 2023-09-25 18:31 ` Christophe Leroy
  2023-09-25 18:31 ` [PATCH v2 18/37] powerpc/nohash: Refactor pte_clear() Christophe Leroy
                   ` (21 subsequent siblings)
  38 siblings, 0 replies; 50+ messages in thread
From: Christophe Leroy @ 2023-09-25 18:31 UTC (permalink / raw)
  To: Michael Ellerman, Nicholas Piggin; +Cc: linuxppc-dev, linux-kernel

ptep_set_wrprotect() and ptep_get_and_clear are identical for
nohash/32 and nohash/64.

Make them common.

Signed-off-by: Christophe Leroy <christophe.leroy@csgroup.eu>
---
 arch/powerpc/include/asm/nohash/32/pgtable.h | 16 ----------------
 arch/powerpc/include/asm/nohash/64/pgtable.h | 15 ---------------
 arch/powerpc/include/asm/nohash/pgtable.h    | 16 ++++++++++++++++
 3 files changed, 16 insertions(+), 31 deletions(-)

diff --git a/arch/powerpc/include/asm/nohash/32/pgtable.h b/arch/powerpc/include/asm/nohash/32/pgtable.h
index b7605000bd91..0be464af4cb1 100644
--- a/arch/powerpc/include/asm/nohash/32/pgtable.h
+++ b/arch/powerpc/include/asm/nohash/32/pgtable.h
@@ -164,22 +164,6 @@ static inline void pmd_clear(pmd_t *pmdp)
 	*pmdp = __pmd(0);
 }
 
-#define __HAVE_ARCH_PTEP_GET_AND_CLEAR
-static inline pte_t ptep_get_and_clear(struct mm_struct *mm, unsigned long addr,
-				       pte_t *ptep)
-{
-	return __pte(pte_update(mm, addr, ptep, ~0, 0, 0));
-}
-
-#define __HAVE_ARCH_PTEP_SET_WRPROTECT
-#ifndef ptep_set_wrprotect
-static inline void ptep_set_wrprotect(struct mm_struct *mm, unsigned long addr,
-				      pte_t *ptep)
-{
-	pte_update(mm, addr, ptep, _PAGE_RW, 0, 0);
-}
-#endif
-
 #ifndef __ptep_set_access_flags
 static inline void __ptep_set_access_flags(struct vm_area_struct *vma,
 					   pte_t *ptep, pte_t entry,
diff --git a/arch/powerpc/include/asm/nohash/64/pgtable.h b/arch/powerpc/include/asm/nohash/64/pgtable.h
index 56041036fa34..dc6e35c3a53f 100644
--- a/arch/powerpc/include/asm/nohash/64/pgtable.h
+++ b/arch/powerpc/include/asm/nohash/64/pgtable.h
@@ -145,13 +145,6 @@ static inline void p4d_set(p4d_t *p4dp, unsigned long val)
 	*p4dp = __p4d(val);
 }
 
-#define __HAVE_ARCH_PTEP_SET_WRPROTECT
-static inline void ptep_set_wrprotect(struct mm_struct *mm, unsigned long addr,
-				      pte_t *ptep)
-{
-	pte_update(mm, addr, ptep, _PAGE_RW, 0, 0);
-}
-
 #define __HAVE_ARCH_HUGE_PTEP_SET_WRPROTECT
 static inline void huge_ptep_set_wrprotect(struct mm_struct *mm,
 					   unsigned long addr, pte_t *ptep)
@@ -166,14 +159,6 @@ static inline void huge_ptep_set_wrprotect(struct mm_struct *mm,
 	__young;							\
 })
 
-#define __HAVE_ARCH_PTEP_GET_AND_CLEAR
-static inline pte_t ptep_get_and_clear(struct mm_struct *mm,
-				       unsigned long addr, pte_t *ptep)
-{
-	unsigned long old = pte_update(mm, addr, ptep, ~0UL, 0, 0);
-	return __pte(old);
-}
-
 static inline void pte_clear(struct mm_struct *mm, unsigned long addr,
 			     pte_t * ptep)
 {
diff --git a/arch/powerpc/include/asm/nohash/pgtable.h b/arch/powerpc/include/asm/nohash/pgtable.h
index 2b043b72f642..7e810a84ac15 100644
--- a/arch/powerpc/include/asm/nohash/pgtable.h
+++ b/arch/powerpc/include/asm/nohash/pgtable.h
@@ -80,6 +80,22 @@ static inline int ptep_test_and_clear_young(struct vm_area_struct *vma,
 }
 #define __HAVE_ARCH_PTEP_TEST_AND_CLEAR_YOUNG
 
+#ifndef ptep_set_wrprotect
+static inline void ptep_set_wrprotect(struct mm_struct *mm, unsigned long addr,
+				      pte_t *ptep)
+{
+	pte_update(mm, addr, ptep, _PAGE_RW, 0, 0);
+}
+#endif
+#define __HAVE_ARCH_PTEP_SET_WRPROTECT
+
+static inline pte_t ptep_get_and_clear(struct mm_struct *mm, unsigned long addr,
+				       pte_t *ptep)
+{
+	return __pte(pte_update(mm, addr, ptep, ~0UL, 0, 0));
+}
+#define __HAVE_ARCH_PTEP_GET_AND_CLEAR
+
 /* Generic accessors to PTE bits */
 #ifndef pte_mkwrite_novma
 static inline pte_t pte_mkwrite_novma(pte_t pte)
-- 
2.41.0


^ permalink raw reply related	[flat|nested] 50+ messages in thread

* [PATCH v2 18/37] powerpc/nohash: Refactor pte_clear()
  2023-09-25 18:31 [PATCH v2 00/37] Implement execute-only protection on powerpc Christophe Leroy
                   ` (16 preceding siblings ...)
  2023-09-25 18:31 ` [PATCH v2 17/37] powerpc/nohash: Deduplicate ptep_set_wrprotect() and ptep_get_and_clear() Christophe Leroy
@ 2023-09-25 18:31 ` Christophe Leroy
  2023-09-25 18:31 ` [PATCH v2 19/37] powerpc/nohash: Refactor __ptep_set_access_flags() Christophe Leroy
                   ` (20 subsequent siblings)
  38 siblings, 0 replies; 50+ messages in thread
From: Christophe Leroy @ 2023-09-25 18:31 UTC (permalink / raw)
  To: Michael Ellerman, Nicholas Piggin; +Cc: linuxppc-dev, linux-kernel

pte_clear() are doing the same on nohash/32 and nohash/64,

Keep the static inline version of nohash/64, make it common and
remove the macro version of nohash/32.

Signed-off-by: Christophe Leroy <christophe.leroy@csgroup.eu>
---
 arch/powerpc/include/asm/nohash/32/pgtable.h | 3 ---
 arch/powerpc/include/asm/nohash/64/pgtable.h | 7 -------
 arch/powerpc/include/asm/nohash/pgtable.h    | 6 ++++++
 3 files changed, 6 insertions(+), 10 deletions(-)

diff --git a/arch/powerpc/include/asm/nohash/32/pgtable.h b/arch/powerpc/include/asm/nohash/32/pgtable.h
index 0be464af4cb1..481594097f46 100644
--- a/arch/powerpc/include/asm/nohash/32/pgtable.h
+++ b/arch/powerpc/include/asm/nohash/32/pgtable.h
@@ -153,9 +153,6 @@
 
 #ifndef __ASSEMBLY__
 
-#define pte_clear(mm, addr, ptep) \
-	do { pte_update(mm, addr, ptep, ~0, 0, 0); } while (0)
-
 #define pmd_none(pmd)		(!pmd_val(pmd))
 #define	pmd_bad(pmd)		(pmd_val(pmd) & _PMD_BAD)
 #define	pmd_present(pmd)	(pmd_val(pmd) & _PMD_PRESENT_MASK)
diff --git a/arch/powerpc/include/asm/nohash/64/pgtable.h b/arch/powerpc/include/asm/nohash/64/pgtable.h
index dc6e35c3a53f..b59fbf754f82 100644
--- a/arch/powerpc/include/asm/nohash/64/pgtable.h
+++ b/arch/powerpc/include/asm/nohash/64/pgtable.h
@@ -159,13 +159,6 @@ static inline void huge_ptep_set_wrprotect(struct mm_struct *mm,
 	__young;							\
 })
 
-static inline void pte_clear(struct mm_struct *mm, unsigned long addr,
-			     pte_t * ptep)
-{
-	pte_update(mm, addr, ptep, ~0UL, 0, 0);
-}
-
-
 /* Set the dirty and/or accessed bits atomically in a linux PTE */
 static inline void __ptep_set_access_flags(struct vm_area_struct *vma,
 					   pte_t *ptep, pte_t entry,
diff --git a/arch/powerpc/include/asm/nohash/pgtable.h b/arch/powerpc/include/asm/nohash/pgtable.h
index 7e810a84ac15..464eb771db82 100644
--- a/arch/powerpc/include/asm/nohash/pgtable.h
+++ b/arch/powerpc/include/asm/nohash/pgtable.h
@@ -96,6 +96,12 @@ static inline pte_t ptep_get_and_clear(struct mm_struct *mm, unsigned long addr,
 }
 #define __HAVE_ARCH_PTEP_GET_AND_CLEAR
 
+static inline void pte_clear(struct mm_struct *mm, unsigned long addr,
+			     pte_t * ptep)
+{
+	pte_update(mm, addr, ptep, ~0UL, 0, 0);
+}
+
 /* Generic accessors to PTE bits */
 #ifndef pte_mkwrite_novma
 static inline pte_t pte_mkwrite_novma(pte_t pte)
-- 
2.41.0


^ permalink raw reply related	[flat|nested] 50+ messages in thread

* [PATCH v2 19/37] powerpc/nohash: Refactor __ptep_set_access_flags()
  2023-09-25 18:31 [PATCH v2 00/37] Implement execute-only protection on powerpc Christophe Leroy
                   ` (17 preceding siblings ...)
  2023-09-25 18:31 ` [PATCH v2 18/37] powerpc/nohash: Refactor pte_clear() Christophe Leroy
@ 2023-09-25 18:31 ` Christophe Leroy
  2023-09-25 18:31 ` [PATCH v2 20/37] powerpc/e500: Simplify pte_mkexec() Christophe Leroy
                   ` (19 subsequent siblings)
  38 siblings, 0 replies; 50+ messages in thread
From: Christophe Leroy @ 2023-09-25 18:31 UTC (permalink / raw)
  To: Michael Ellerman, Nicholas Piggin; +Cc: linuxppc-dev, linux-kernel

nohash/32 version of __ptep_set_access_flags() does the same
as nohash/64 version, the only difference is that nohash/32
version is more complete and uses pte_update().

Make it common and remove the nohash/64 version.

Signed-off-by: Christophe Leroy <christophe.leroy@csgroup.eu>
---
 arch/powerpc/include/asm/nohash/32/pgtable.h | 16 ----------------
 arch/powerpc/include/asm/nohash/64/pgtable.h | 15 ---------------
 arch/powerpc/include/asm/nohash/pgtable.h    | 17 +++++++++++++++++
 3 files changed, 17 insertions(+), 31 deletions(-)

diff --git a/arch/powerpc/include/asm/nohash/32/pgtable.h b/arch/powerpc/include/asm/nohash/32/pgtable.h
index 481594097f46..9164a9e41b02 100644
--- a/arch/powerpc/include/asm/nohash/32/pgtable.h
+++ b/arch/powerpc/include/asm/nohash/32/pgtable.h
@@ -161,22 +161,6 @@ static inline void pmd_clear(pmd_t *pmdp)
 	*pmdp = __pmd(0);
 }
 
-#ifndef __ptep_set_access_flags
-static inline void __ptep_set_access_flags(struct vm_area_struct *vma,
-					   pte_t *ptep, pte_t entry,
-					   unsigned long address,
-					   int psize)
-{
-	unsigned long set = pte_val(entry) &
-			    (_PAGE_DIRTY | _PAGE_ACCESSED | _PAGE_RW | _PAGE_EXEC);
-	int huge = psize > mmu_virtual_psize ? 1 : 0;
-
-	pte_update(vma->vm_mm, address, ptep, 0, set, huge);
-
-	flush_tlb_page(vma, address);
-}
-#endif
-
 /*
  * Note that on Book E processors, the pmd contains the kernel virtual
  * (lowmem) address of the pte page.  The physical address is less useful
diff --git a/arch/powerpc/include/asm/nohash/64/pgtable.h b/arch/powerpc/include/asm/nohash/64/pgtable.h
index b59fbf754f82..36b9bad428cc 100644
--- a/arch/powerpc/include/asm/nohash/64/pgtable.h
+++ b/arch/powerpc/include/asm/nohash/64/pgtable.h
@@ -159,21 +159,6 @@ static inline void huge_ptep_set_wrprotect(struct mm_struct *mm,
 	__young;							\
 })
 
-/* Set the dirty and/or accessed bits atomically in a linux PTE */
-static inline void __ptep_set_access_flags(struct vm_area_struct *vma,
-					   pte_t *ptep, pte_t entry,
-					   unsigned long address,
-					   int psize)
-{
-	unsigned long bits = pte_val(entry) &
-		(_PAGE_DIRTY | _PAGE_ACCESSED | _PAGE_RW | _PAGE_EXEC);
-
-	unsigned long old = pte_val(*ptep);
-	*ptep = __pte(old | bits);
-
-	flush_tlb_page(vma, address);
-}
-
 #define pmd_ERROR(e) \
 	pr_err("%s:%d: bad pmd %08lx.\n", __FILE__, __LINE__, pmd_val(e))
 #define pgd_ERROR(e) \
diff --git a/arch/powerpc/include/asm/nohash/pgtable.h b/arch/powerpc/include/asm/nohash/pgtable.h
index 464eb771db82..1493f0b09ae9 100644
--- a/arch/powerpc/include/asm/nohash/pgtable.h
+++ b/arch/powerpc/include/asm/nohash/pgtable.h
@@ -102,6 +102,23 @@ static inline void pte_clear(struct mm_struct *mm, unsigned long addr,
 	pte_update(mm, addr, ptep, ~0UL, 0, 0);
 }
 
+/* Set the dirty and/or accessed bits atomically in a linux PTE */
+#ifndef __ptep_set_access_flags
+static inline void __ptep_set_access_flags(struct vm_area_struct *vma,
+					   pte_t *ptep, pte_t entry,
+					   unsigned long address,
+					   int psize)
+{
+	unsigned long set = pte_val(entry) &
+			    (_PAGE_DIRTY | _PAGE_ACCESSED | _PAGE_RW | _PAGE_EXEC);
+	int huge = psize > mmu_virtual_psize ? 1 : 0;
+
+	pte_update(vma->vm_mm, address, ptep, 0, set, huge);
+
+	flush_tlb_page(vma, address);
+}
+#endif
+
 /* Generic accessors to PTE bits */
 #ifndef pte_mkwrite_novma
 static inline pte_t pte_mkwrite_novma(pte_t pte)
-- 
2.41.0


^ permalink raw reply related	[flat|nested] 50+ messages in thread

* [PATCH v2 20/37] powerpc/e500: Simplify pte_mkexec()
  2023-09-25 18:31 [PATCH v2 00/37] Implement execute-only protection on powerpc Christophe Leroy
                   ` (18 preceding siblings ...)
  2023-09-25 18:31 ` [PATCH v2 19/37] powerpc/nohash: Refactor __ptep_set_access_flags() Christophe Leroy
@ 2023-09-25 18:31 ` Christophe Leroy
  2023-09-25 18:31 ` [PATCH v2 21/37] powerpc: Implement and use pgprot_nx() Christophe Leroy
                   ` (18 subsequent siblings)
  38 siblings, 0 replies; 50+ messages in thread
From: Christophe Leroy @ 2023-09-25 18:31 UTC (permalink / raw)
  To: Michael Ellerman, Nicholas Piggin; +Cc: linuxppc-dev, linux-kernel

Commit b6cb20fdc273 ("powerpc/book3e: Fix set_memory_x() and
set_memory_nx()") implemented a more elaborated version of
pte_mkwrite() suitable for both kernel and user pages. That was
needed because set_memory_x() was using pte_mkwrite(). But since
commit a4c182ecf335 ("powerpc/set_memory: Avoid spinlock recursion
in change_page_attr()") pte_mkwrite() is not used anymore by
set_memory_x() so pte_mkwrite() can be simplified as it is only
used for user pages.

Signed-off-by: Christophe Leroy <christophe.leroy@csgroup.eu>
---
 arch/powerpc/include/asm/nohash/pte-e500.h | 5 +----
 1 file changed, 1 insertion(+), 4 deletions(-)

diff --git a/arch/powerpc/include/asm/nohash/pte-e500.h b/arch/powerpc/include/asm/nohash/pte-e500.h
index d8924cbd61e4..99288e26b6b0 100644
--- a/arch/powerpc/include/asm/nohash/pte-e500.h
+++ b/arch/powerpc/include/asm/nohash/pte-e500.h
@@ -115,10 +115,7 @@ static inline pte_t pte_mkuser(pte_t pte)
 
 static inline pte_t pte_mkexec(pte_t pte)
 {
-	if (pte_val(pte) & _PAGE_BAP_UR)
-		return __pte((pte_val(pte) & ~_PAGE_BAP_SX) | _PAGE_BAP_UX);
-	else
-		return __pte((pte_val(pte) & ~_PAGE_BAP_UX) | _PAGE_BAP_SX);
+	return __pte((pte_val(pte) & ~_PAGE_BAP_SX) | _PAGE_BAP_UX);
 }
 #define pte_mkexec pte_mkexec
 
-- 
2.41.0


^ permalink raw reply related	[flat|nested] 50+ messages in thread

* [PATCH v2 21/37] powerpc: Implement and use pgprot_nx()
  2023-09-25 18:31 [PATCH v2 00/37] Implement execute-only protection on powerpc Christophe Leroy
                   ` (19 preceding siblings ...)
  2023-09-25 18:31 ` [PATCH v2 20/37] powerpc/e500: Simplify pte_mkexec() Christophe Leroy
@ 2023-09-25 18:31 ` Christophe Leroy
  2023-09-25 18:31 ` [PATCH v2 22/37] powerpc: Fail ioremap() instead of silently ignoring flags when PAGE_USER is set Christophe Leroy
                   ` (17 subsequent siblings)
  38 siblings, 0 replies; 50+ messages in thread
From: Christophe Leroy @ 2023-09-25 18:31 UTC (permalink / raw)
  To: Michael Ellerman, Nicholas Piggin; +Cc: linuxppc-dev, linux-kernel

ioremap_page_range() calls pgprot_nx() vmap() and vmap_pfn()
clear execute permission by calling pgprot_nx().

When pgprot_nx() is not defined it falls back to a nop.

Implement it for powerpc then use it in early_ioremap_range().

Then the call to pte_exprotect() can be removed from ioremap_prot().

Signed-off-by: Christophe Leroy <christophe.leroy@csgroup.eu>
---
 arch/powerpc/include/asm/pgtable.h | 6 ++++++
 arch/powerpc/mm/ioremap.c          | 5 ++---
 2 files changed, 8 insertions(+), 3 deletions(-)

diff --git a/arch/powerpc/include/asm/pgtable.h b/arch/powerpc/include/asm/pgtable.h
index 966e7c5119f6..2bfb7dd3b49e 100644
--- a/arch/powerpc/include/asm/pgtable.h
+++ b/arch/powerpc/include/asm/pgtable.h
@@ -71,6 +71,12 @@ static inline pgprot_t pte_pgprot(pte_t pte)
 	return __pgprot(pte_flags);
 }
 
+static inline pgprot_t pgprot_nx(pgprot_t prot)
+{
+	return pte_pgprot(pte_exprotect(__pte(pgprot_val(prot))));
+}
+#define pgprot_nx pgprot_nx
+
 #ifndef pmd_page_vaddr
 static inline const void *pmd_page_vaddr(pmd_t pmd)
 {
diff --git a/arch/powerpc/mm/ioremap.c b/arch/powerpc/mm/ioremap.c
index 705e8e8ffde4..d5159f205380 100644
--- a/arch/powerpc/mm/ioremap.c
+++ b/arch/powerpc/mm/ioremap.c
@@ -50,8 +50,7 @@ void __iomem *ioremap_prot(phys_addr_t addr, size_t size, unsigned long flags)
 	if (pte_write(pte))
 		pte = pte_mkdirty(pte);
 
-	/* we don't want to let _PAGE_USER and _PAGE_EXEC leak out */
-	pte = pte_exprotect(pte);
+	/* we don't want to let _PAGE_USER leak out */
 	pte = pte_mkprivileged(pte);
 
 	if (iowa_is_active())
@@ -66,7 +65,7 @@ int early_ioremap_range(unsigned long ea, phys_addr_t pa,
 	unsigned long i;
 
 	for (i = 0; i < size; i += PAGE_SIZE) {
-		int err = map_kernel_page(ea + i, pa + i, prot);
+		int err = map_kernel_page(ea + i, pa + i, pgprot_nx(prot));
 
 		if (WARN_ON_ONCE(err))  /* Should clean up */
 			return err;
-- 
2.41.0


^ permalink raw reply related	[flat|nested] 50+ messages in thread

* [PATCH v2 22/37] powerpc: Fail ioremap() instead of silently ignoring flags when PAGE_USER is set
  2023-09-25 18:31 [PATCH v2 00/37] Implement execute-only protection on powerpc Christophe Leroy
                   ` (20 preceding siblings ...)
  2023-09-25 18:31 ` [PATCH v2 21/37] powerpc: Implement and use pgprot_nx() Christophe Leroy
@ 2023-09-25 18:31 ` Christophe Leroy
  2023-09-25 18:31 ` [PATCH v2 23/37] powerpc: Remove pte_mkuser() and pte_mkpriviledged() Christophe Leroy
                   ` (16 subsequent siblings)
  38 siblings, 0 replies; 50+ messages in thread
From: Christophe Leroy @ 2023-09-25 18:31 UTC (permalink / raw)
  To: Michael Ellerman, Nicholas Piggin; +Cc: linuxppc-dev, linux-kernel

Calling ioremap() with _PAGE_USER (or _PAGE_PRIVILEDGE unset)
is wrong. Loudly fail the call to ioremap() instead of blindly
clearing the flags.

Signed-off-by: Christophe Leroy <christophe.leroy@csgroup.eu>
---
 arch/powerpc/mm/ioremap.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/arch/powerpc/mm/ioremap.c b/arch/powerpc/mm/ioremap.c
index d5159f205380..7823c38f09de 100644
--- a/arch/powerpc/mm/ioremap.c
+++ b/arch/powerpc/mm/ioremap.c
@@ -51,7 +51,8 @@ void __iomem *ioremap_prot(phys_addr_t addr, size_t size, unsigned long flags)
 		pte = pte_mkdirty(pte);
 
 	/* we don't want to let _PAGE_USER leak out */
-	pte = pte_mkprivileged(pte);
+	if (WARN_ON(pte_user(pte)))
+		return NULL;
 
 	if (iowa_is_active())
 		return iowa_ioremap(addr, size, pte_pgprot(pte), caller);
-- 
2.41.0


^ permalink raw reply related	[flat|nested] 50+ messages in thread

* [PATCH v2 23/37] powerpc: Remove pte_mkuser() and pte_mkpriviledged()
  2023-09-25 18:31 [PATCH v2 00/37] Implement execute-only protection on powerpc Christophe Leroy
                   ` (21 preceding siblings ...)
  2023-09-25 18:31 ` [PATCH v2 22/37] powerpc: Fail ioremap() instead of silently ignoring flags when PAGE_USER is set Christophe Leroy
@ 2023-09-25 18:31 ` Christophe Leroy
  2023-09-25 18:31 ` [PATCH v2 24/37] powerpc: Rely on address instead of pte_user() Christophe Leroy
                   ` (15 subsequent siblings)
  38 siblings, 0 replies; 50+ messages in thread
From: Christophe Leroy @ 2023-09-25 18:31 UTC (permalink / raw)
  To: Michael Ellerman, Nicholas Piggin; +Cc: linuxppc-dev, linux-kernel

pte_mkuser() is never used. Remove it.

pte_mkpriviledged() is not used anymore. Remove it too.

Signed-off-by: Christophe Leroy <christophe.leroy@csgroup.eu>
---
 arch/powerpc/include/asm/book3s/32/pgtable.h | 10 ----------
 arch/powerpc/include/asm/book3s/64/pgtable.h | 10 ----------
 arch/powerpc/include/asm/nohash/32/pte-8xx.h | 14 --------------
 arch/powerpc/include/asm/nohash/pgtable.h    | 14 --------------
 arch/powerpc/include/asm/nohash/pte-e500.h   | 15 ---------------
 5 files changed, 63 deletions(-)

diff --git a/arch/powerpc/include/asm/book3s/32/pgtable.h b/arch/powerpc/include/asm/book3s/32/pgtable.h
index 45b69ae2631e..80505915c77c 100644
--- a/arch/powerpc/include/asm/book3s/32/pgtable.h
+++ b/arch/powerpc/include/asm/book3s/32/pgtable.h
@@ -522,16 +522,6 @@ static inline pte_t pte_mkhuge(pte_t pte)
 	return pte;
 }
 
-static inline pte_t pte_mkprivileged(pte_t pte)
-{
-	return __pte(pte_val(pte) & ~_PAGE_USER);
-}
-
-static inline pte_t pte_mkuser(pte_t pte)
-{
-	return __pte(pte_val(pte) | _PAGE_USER);
-}
-
 static inline pte_t pte_modify(pte_t pte, pgprot_t newprot)
 {
 	return __pte((pte_val(pte) & _PAGE_CHG_MASK) | pgprot_val(newprot));
diff --git a/arch/powerpc/include/asm/book3s/64/pgtable.h b/arch/powerpc/include/asm/book3s/64/pgtable.h
index dbd545e73161..c3b921769ece 100644
--- a/arch/powerpc/include/asm/book3s/64/pgtable.h
+++ b/arch/powerpc/include/asm/book3s/64/pgtable.h
@@ -630,16 +630,6 @@ static inline pte_t pte_mkdevmap(pte_t pte)
 	return __pte_raw(pte_raw(pte) | cpu_to_be64(_PAGE_SPECIAL | _PAGE_DEVMAP));
 }
 
-static inline pte_t pte_mkprivileged(pte_t pte)
-{
-	return __pte_raw(pte_raw(pte) | cpu_to_be64(_PAGE_PRIVILEGED));
-}
-
-static inline pte_t pte_mkuser(pte_t pte)
-{
-	return __pte_raw(pte_raw(pte) & cpu_to_be64(~_PAGE_PRIVILEGED));
-}
-
 /*
  * This is potentially called with a pmd as the argument, in which case it's not
  * safe to check _PAGE_DEVMAP unless we also confirm that _PAGE_PTE is set.
diff --git a/arch/powerpc/include/asm/nohash/32/pte-8xx.h b/arch/powerpc/include/asm/nohash/32/pte-8xx.h
index 52395a5ecd70..843fe0138a66 100644
--- a/arch/powerpc/include/asm/nohash/32/pte-8xx.h
+++ b/arch/powerpc/include/asm/nohash/32/pte-8xx.h
@@ -122,20 +122,6 @@ static inline bool pte_user(pte_t pte)
 
 #define pte_user pte_user
 
-static inline pte_t pte_mkprivileged(pte_t pte)
-{
-	return __pte(pte_val(pte) | _PAGE_SH);
-}
-
-#define pte_mkprivileged pte_mkprivileged
-
-static inline pte_t pte_mkuser(pte_t pte)
-{
-	return __pte(pte_val(pte) & ~_PAGE_SH);
-}
-
-#define pte_mkuser pte_mkuser
-
 static inline pte_t pte_mkhuge(pte_t pte)
 {
 	return __pte(pte_val(pte) | _PAGE_SPS | _PAGE_HUGE);
diff --git a/arch/powerpc/include/asm/nohash/pgtable.h b/arch/powerpc/include/asm/nohash/pgtable.h
index 1493f0b09ae9..9619beae4454 100644
--- a/arch/powerpc/include/asm/nohash/pgtable.h
+++ b/arch/powerpc/include/asm/nohash/pgtable.h
@@ -252,20 +252,6 @@ static inline pte_t pte_mkhuge(pte_t pte)
 }
 #endif
 
-#ifndef pte_mkprivileged
-static inline pte_t pte_mkprivileged(pte_t pte)
-{
-	return __pte(pte_val(pte) & ~_PAGE_USER);
-}
-#endif
-
-#ifndef pte_mkuser
-static inline pte_t pte_mkuser(pte_t pte)
-{
-	return __pte(pte_val(pte) | _PAGE_USER);
-}
-#endif
-
 static inline pte_t pte_modify(pte_t pte, pgprot_t newprot)
 {
 	return __pte((pte_val(pte) & _PAGE_CHG_MASK) | pgprot_val(newprot));
diff --git a/arch/powerpc/include/asm/nohash/pte-e500.h b/arch/powerpc/include/asm/nohash/pte-e500.h
index 99288e26b6b0..9f9e3f02d414 100644
--- a/arch/powerpc/include/asm/nohash/pte-e500.h
+++ b/arch/powerpc/include/asm/nohash/pte-e500.h
@@ -54,7 +54,6 @@
 #define _PAGE_KERNEL_RWX	(_PAGE_BAP_SW | _PAGE_BAP_SR | _PAGE_DIRTY | _PAGE_BAP_SX)
 #define _PAGE_KERNEL_ROX	(_PAGE_BAP_SR | _PAGE_BAP_SX)
 #define _PAGE_USER		(_PAGE_BAP_UR | _PAGE_BAP_SR) /* Can be read */
-#define _PAGE_PRIVILEGED	(_PAGE_BAP_SR)
 
 #define _PAGE_SPECIAL	_PAGE_SW0
 
@@ -99,20 +98,6 @@
 #define PAGE_READONLY_X	__pgprot(_PAGE_BASE | _PAGE_USER | _PAGE_BAP_UX)
 
 #ifndef __ASSEMBLY__
-static inline pte_t pte_mkprivileged(pte_t pte)
-{
-	return __pte((pte_val(pte) & ~_PAGE_USER) | _PAGE_PRIVILEGED);
-}
-
-#define pte_mkprivileged pte_mkprivileged
-
-static inline pte_t pte_mkuser(pte_t pte)
-{
-	return __pte((pte_val(pte) & ~_PAGE_PRIVILEGED) | _PAGE_USER);
-}
-
-#define pte_mkuser pte_mkuser
-
 static inline pte_t pte_mkexec(pte_t pte)
 {
 	return __pte((pte_val(pte) & ~_PAGE_BAP_SX) | _PAGE_BAP_UX);
-- 
2.41.0


^ permalink raw reply related	[flat|nested] 50+ messages in thread

* [PATCH v2 24/37] powerpc: Rely on address instead of pte_user()
  2023-09-25 18:31 [PATCH v2 00/37] Implement execute-only protection on powerpc Christophe Leroy
                   ` (22 preceding siblings ...)
  2023-09-25 18:31 ` [PATCH v2 23/37] powerpc: Remove pte_mkuser() and pte_mkpriviledged() Christophe Leroy
@ 2023-09-25 18:31 ` Christophe Leroy
  2023-09-25 18:31 ` [PATCH v2 25/37] powerpc: Refactor permission masks used for __P/__S table and kernel memory flags Christophe Leroy
                   ` (14 subsequent siblings)
  38 siblings, 0 replies; 50+ messages in thread
From: Christophe Leroy @ 2023-09-25 18:31 UTC (permalink / raw)
  To: Michael Ellerman, Nicholas Piggin; +Cc: linuxppc-dev, linux-kernel

pte_user() may return 'false' when a user page is PAGE_NONE.

In that case it is still a user page and needs to be handled
as such. So use is_kernel_addr() instead.

And remove "user" text from ptdump as ptdump only dumps
kernel tables.

Note: no change done for book3s/64 which still has it
'priviledge' bit.

Signed-off-by: Christophe Leroy <christophe.leroy@csgroup.eu>
---
 arch/powerpc/include/asm/nohash/pgtable.h |  2 +-
 arch/powerpc/mm/book3s32/mmu.c            |  4 ++--
 arch/powerpc/mm/nohash/e500.c             |  2 +-
 arch/powerpc/mm/pgtable.c                 | 22 +++++++++++-----------
 arch/powerpc/mm/ptdump/8xx.c              |  5 -----
 arch/powerpc/mm/ptdump/shared.c           |  5 -----
 6 files changed, 15 insertions(+), 25 deletions(-)

diff --git a/arch/powerpc/include/asm/nohash/pgtable.h b/arch/powerpc/include/asm/nohash/pgtable.h
index 9619beae4454..200f2dbf48e2 100644
--- a/arch/powerpc/include/asm/nohash/pgtable.h
+++ b/arch/powerpc/include/asm/nohash/pgtable.h
@@ -58,7 +58,7 @@ static inline pte_basic_t pte_update(struct mm_struct *mm, unsigned long addr, p
 
 	*p = __pte(new);
 
-	if (IS_ENABLED(CONFIG_44x) && (old & _PAGE_USER) && (old & _PAGE_EXEC))
+	if (IS_ENABLED(CONFIG_44x) && !is_kernel_addr(addr) && (old & _PAGE_EXEC))
 		icache_44x_need_flush = 1;
 
 	/* huge pages use the old page table lock */
diff --git a/arch/powerpc/mm/book3s32/mmu.c b/arch/powerpc/mm/book3s32/mmu.c
index 850783cfa9c7..d1041c946ce2 100644
--- a/arch/powerpc/mm/book3s32/mmu.c
+++ b/arch/powerpc/mm/book3s32/mmu.c
@@ -127,7 +127,7 @@ static void setibat(int index, unsigned long virt, phys_addr_t phys,
 	wimgxpp = (flags & _PAGE_COHERENT) | (_PAGE_EXEC ? BPP_RX : BPP_XX);
 	bat[0].batu = virt | (bl << 2) | 2; /* Vs=1, Vp=0 */
 	bat[0].batl = BAT_PHYS_ADDR(phys) | wimgxpp;
-	if (flags & _PAGE_USER)
+	if (!is_kernel_addr(virt))
 		bat[0].batu |= 1;	/* Vp = 1 */
 }
 
@@ -280,7 +280,7 @@ void __init setbat(int index, unsigned long virt, phys_addr_t phys,
 	wimgxpp |= (flags & _PAGE_RW)? BPP_RW: BPP_RX;
 	bat[1].batu = virt | (bl << 2) | 2; /* Vs=1, Vp=0 */
 	bat[1].batl = BAT_PHYS_ADDR(phys) | wimgxpp;
-	if (flags & _PAGE_USER)
+	if (!is_kernel_addr(virt))
 		bat[1].batu |= 1; 	/* Vp = 1 */
 	if (flags & _PAGE_GUARDED) {
 		/* G bit must be zero in IBATs */
diff --git a/arch/powerpc/mm/nohash/e500.c b/arch/powerpc/mm/nohash/e500.c
index 40a4e69ae1a9..5b7d7a932bfd 100644
--- a/arch/powerpc/mm/nohash/e500.c
+++ b/arch/powerpc/mm/nohash/e500.c
@@ -122,7 +122,7 @@ static void settlbcam(int index, unsigned long virt, phys_addr_t phys,
 		TLBCAM[index].MAS7 = (u64)phys >> 32;
 
 	/* Below is unlikely -- only for large user pages or similar */
-	if (pte_user(__pte(flags))) {
+	if (!is_kernel_addr(virt)) {
 		TLBCAM[index].MAS3 |= MAS3_UR;
 		TLBCAM[index].MAS3 |= (flags & _PAGE_EXEC) ? MAS3_UX : 0;
 		TLBCAM[index].MAS3 |= (flags & _PAGE_RW) ? MAS3_UW : 0;
diff --git a/arch/powerpc/mm/pgtable.c b/arch/powerpc/mm/pgtable.c
index 3f86fd217690..781a68c69c2f 100644
--- a/arch/powerpc/mm/pgtable.c
+++ b/arch/powerpc/mm/pgtable.c
@@ -46,13 +46,13 @@ static inline int is_exec_fault(void)
  * and we avoid _PAGE_SPECIAL and cache inhibited pte. We also only do that
  * on userspace PTEs
  */
-static inline int pte_looks_normal(pte_t pte)
+static inline int pte_looks_normal(pte_t pte, unsigned long addr)
 {
 
 	if (pte_present(pte) && !pte_special(pte)) {
 		if (pte_ci(pte))
 			return 0;
-		if (pte_user(pte))
+		if (!is_kernel_addr(addr))
 			return 1;
 	}
 	return 0;
@@ -79,11 +79,11 @@ static struct folio *maybe_pte_to_folio(pte_t pte)
  * support falls into the same category.
  */
 
-static pte_t set_pte_filter_hash(pte_t pte)
+static pte_t set_pte_filter_hash(pte_t pte, unsigned long addr)
 {
 	pte = __pte(pte_val(pte) & ~_PAGE_HPTEFLAGS);
-	if (pte_looks_normal(pte) && !(cpu_has_feature(CPU_FTR_COHERENT_ICACHE) ||
-				       cpu_has_feature(CPU_FTR_NOEXECUTE))) {
+	if (pte_looks_normal(pte, addr) && !(cpu_has_feature(CPU_FTR_COHERENT_ICACHE) ||
+					     cpu_has_feature(CPU_FTR_NOEXECUTE))) {
 		struct folio *folio = maybe_pte_to_folio(pte);
 		if (!folio)
 			return pte;
@@ -97,7 +97,7 @@ static pte_t set_pte_filter_hash(pte_t pte)
 
 #else /* CONFIG_PPC_BOOK3S */
 
-static pte_t set_pte_filter_hash(pte_t pte) { return pte; }
+static pte_t set_pte_filter_hash(pte_t pte, unsigned long addr) { return pte; }
 
 #endif /* CONFIG_PPC_BOOK3S */
 
@@ -105,7 +105,7 @@ static pte_t set_pte_filter_hash(pte_t pte) { return pte; }
  * as we don't have two bits to spare for _PAGE_EXEC and _PAGE_HWEXEC so
  * instead we "filter out" the exec permission for non clean pages.
  */
-static inline pte_t set_pte_filter(pte_t pte)
+static inline pte_t set_pte_filter(pte_t pte, unsigned long addr)
 {
 	struct folio *folio;
 
@@ -113,10 +113,10 @@ static inline pte_t set_pte_filter(pte_t pte)
 		return pte;
 
 	if (mmu_has_feature(MMU_FTR_HPTE_TABLE))
-		return set_pte_filter_hash(pte);
+		return set_pte_filter_hash(pte, addr);
 
 	/* No exec permission in the first place, move on */
-	if (!pte_exec(pte) || !pte_looks_normal(pte))
+	if (!pte_exec(pte) || !pte_looks_normal(pte, addr))
 		return pte;
 
 	/* If you set _PAGE_EXEC on weird pages you're on your own */
@@ -200,7 +200,7 @@ void set_ptes(struct mm_struct *mm, unsigned long addr, pte_t *ptep,
 	 * this context might not have been activated yet when this
 	 * is called.
 	 */
-	pte = set_pte_filter(pte);
+	pte = set_pte_filter(pte, addr);
 
 	/* Perform the setting of the PTE */
 	arch_enter_lazy_mmu_mode();
@@ -301,7 +301,7 @@ void set_huge_pte_at(struct mm_struct *mm, unsigned long addr, pte_t *ptep, pte_
 	 */
 	VM_WARN_ON(pte_hw_valid(*ptep) && !pte_protnone(*ptep));
 
-	pte = set_pte_filter(pte);
+	pte = set_pte_filter(pte, addr);
 
 	val = pte_val(pte);
 
diff --git a/arch/powerpc/mm/ptdump/8xx.c b/arch/powerpc/mm/ptdump/8xx.c
index fac932eb8f9a..b5c79b11ea3c 100644
--- a/arch/powerpc/mm/ptdump/8xx.c
+++ b/arch/powerpc/mm/ptdump/8xx.c
@@ -20,11 +20,6 @@ static const struct flag_info flag_array[] = {
 #endif
 		.set	= "huge",
 		.clear	= "    ",
-	}, {
-		.mask	= _PAGE_SH,
-		.val	= 0,
-		.set	= "user",
-		.clear	= "    ",
 	}, {
 		.mask	= _PAGE_RO | _PAGE_NA,
 		.val	= 0,
diff --git a/arch/powerpc/mm/ptdump/shared.c b/arch/powerpc/mm/ptdump/shared.c
index f884760ca5cf..5ff101654c45 100644
--- a/arch/powerpc/mm/ptdump/shared.c
+++ b/arch/powerpc/mm/ptdump/shared.c
@@ -11,11 +11,6 @@
 
 static const struct flag_info flag_array[] = {
 	{
-		.mask	= _PAGE_USER,
-		.val	= _PAGE_USER,
-		.set	= "user",
-		.clear	= "    ",
-	}, {
 		.mask	= _PAGE_RW,
 		.val	= 0,
 		.set	= "r ",
-- 
2.41.0


^ permalink raw reply related	[flat|nested] 50+ messages in thread

* [PATCH v2 25/37] powerpc: Refactor permission masks used for __P/__S table and kernel memory flags
  2023-09-25 18:31 [PATCH v2 00/37] Implement execute-only protection on powerpc Christophe Leroy
                   ` (23 preceding siblings ...)
  2023-09-25 18:31 ` [PATCH v2 24/37] powerpc: Rely on address instead of pte_user() Christophe Leroy
@ 2023-09-25 18:31 ` Christophe Leroy
  2023-09-25 18:31 ` [PATCH v2 26/37] powerpc/8xx: Use generic permission masks Christophe Leroy
                   ` (13 subsequent siblings)
  38 siblings, 0 replies; 50+ messages in thread
From: Christophe Leroy @ 2023-09-25 18:31 UTC (permalink / raw)
  To: Michael Ellerman, Nicholas Piggin; +Cc: linuxppc-dev, linux-kernel

Prepare a common version of the permission masks that will be based
on _PAGE_NA, _PAGE_RO, _PAGE_ROX, _PAGE_RW, _PAGE_RWX that will be
defined in platform specific headers in later patches.

Put them in a new header pgtable-masks.h which will be included by
platforms.

And prepare a common version of flags used for mapping kernel memory
that will be based on _PAGE_RO, _PAGE_ROX, _PAGE_RW, _PAGE_RWX that
will be defined in platform specific headers.

Put them in unless _PAGE_KERNEL_RO is already defined so that platform
specific definitions can be dismantled one by one.

Signed-off-by: Christophe Leroy <christophe.leroy@csgroup.eu>
---
 arch/powerpc/include/asm/pgtable-masks.h | 30 ++++++++++++++++++++++++
 1 file changed, 30 insertions(+)
 create mode 100644 arch/powerpc/include/asm/pgtable-masks.h

diff --git a/arch/powerpc/include/asm/pgtable-masks.h b/arch/powerpc/include/asm/pgtable-masks.h
new file mode 100644
index 000000000000..808a3b9e8fc0
--- /dev/null
+++ b/arch/powerpc/include/asm/pgtable-masks.h
@@ -0,0 +1,30 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _ASM_POWERPC_PGTABLE_MASKS_H
+#define _ASM_POWERPC_PGTABLE_MASKS_H
+
+#ifndef _PAGE_NA
+#define _PAGE_NA	0
+#define _PAGE_RO	_PAGE_READ
+#define _PAGE_ROX	(_PAGE_READ | _PAGE_EXEC)
+#define _PAGE_RW	(_PAGE_READ | _PAGE_WRITE)
+#define _PAGE_RWX	(_PAGE_READ | _PAGE_WRITE | _PAGE_EXEC)
+#endif
+
+/* Permission flags for kernel mappings */
+#ifndef _PAGE_KERNEL_RO
+#define _PAGE_KERNEL_RO		_PAGE_RO
+#define _PAGE_KERNEL_ROX	_PAGE_ROX
+#define _PAGE_KERNEL_RW		(_PAGE_RW | _PAGE_DIRTY)
+#define _PAGE_KERNEL_RWX	(_PAGE_RWX | _PAGE_DIRTY)
+#endif
+
+/* Permission masks used to generate the __P and __S table */
+#define PAGE_NONE	__pgprot(_PAGE_BASE | _PAGE_NA)
+#define PAGE_SHARED	__pgprot(_PAGE_BASE | _PAGE_RW)
+#define PAGE_SHARED_X	__pgprot(_PAGE_BASE | _PAGE_RWX)
+#define PAGE_COPY	__pgprot(_PAGE_BASE | _PAGE_RO)
+#define PAGE_COPY_X	__pgprot(_PAGE_BASE | _PAGE_ROX)
+#define PAGE_READONLY	__pgprot(_PAGE_BASE | _PAGE_RO)
+#define PAGE_READONLY_X	__pgprot(_PAGE_BASE | _PAGE_ROX)
+
+#endif /* _ASM_POWERPC_PGTABLE_MASKS_H */
-- 
2.41.0


^ permalink raw reply related	[flat|nested] 50+ messages in thread

* [PATCH v2 26/37] powerpc/8xx: Use generic permission masks
  2023-09-25 18:31 [PATCH v2 00/37] Implement execute-only protection on powerpc Christophe Leroy
                   ` (24 preceding siblings ...)
  2023-09-25 18:31 ` [PATCH v2 25/37] powerpc: Refactor permission masks used for __P/__S table and kernel memory flags Christophe Leroy
@ 2023-09-25 18:31 ` Christophe Leroy
  2023-09-25 18:31 ` [PATCH v2 27/37] powerpc/64s: " Christophe Leroy
                   ` (12 subsequent siblings)
  38 siblings, 0 replies; 50+ messages in thread
From: Christophe Leroy @ 2023-09-25 18:31 UTC (permalink / raw)
  To: Michael Ellerman, Nicholas Piggin; +Cc: linuxppc-dev, linux-kernel

8xx already has _PAGE_NA and _PAGE_RO. So add _PAGE_ROX, _PAGE_RW and
_PAGE_RWX and remove specific permission masks.

Signed-off-by: Christophe Leroy <christophe.leroy@csgroup.eu>
---
 arch/powerpc/include/asm/nohash/32/pte-8xx.h | 13 +++++--------
 1 file changed, 5 insertions(+), 8 deletions(-)

diff --git a/arch/powerpc/include/asm/nohash/32/pte-8xx.h b/arch/powerpc/include/asm/nohash/32/pte-8xx.h
index 843fe0138a66..62c965a4511a 100644
--- a/arch/powerpc/include/asm/nohash/32/pte-8xx.h
+++ b/arch/powerpc/include/asm/nohash/32/pte-8xx.h
@@ -48,6 +48,10 @@
 
 #define _PAGE_HUGE	0x0800	/* Copied to L1 PS bit 29 */
 
+#define _PAGE_ROX	(_PAGE_RO | _PAGE_EXEC)
+#define _PAGE_RW	0
+#define _PAGE_RWX	_PAGE_EXEC
+
 /* cache related flags non existing on 8xx */
 #define _PAGE_COHERENT	0
 #define _PAGE_WRITETHRU	0
@@ -77,14 +81,7 @@
 #define _PAGE_BASE_NC	(_PAGE_PRESENT | _PAGE_ACCESSED | _PAGE_PSIZE)
 #define _PAGE_BASE	(_PAGE_BASE_NC)
 
-/* Permission masks used to generate the __P and __S table */
-#define PAGE_NONE	__pgprot(_PAGE_BASE | _PAGE_NA)
-#define PAGE_SHARED	__pgprot(_PAGE_BASE)
-#define PAGE_SHARED_X	__pgprot(_PAGE_BASE | _PAGE_EXEC)
-#define PAGE_COPY	__pgprot(_PAGE_BASE | _PAGE_RO)
-#define PAGE_COPY_X	__pgprot(_PAGE_BASE | _PAGE_RO | _PAGE_EXEC)
-#define PAGE_READONLY	__pgprot(_PAGE_BASE | _PAGE_RO)
-#define PAGE_READONLY_X	__pgprot(_PAGE_BASE | _PAGE_RO | _PAGE_EXEC)
+#include <asm/pgtable-masks.h>
 
 #ifndef __ASSEMBLY__
 static inline pte_t pte_wrprotect(pte_t pte)
-- 
2.41.0


^ permalink raw reply related	[flat|nested] 50+ messages in thread

* [PATCH v2 27/37] powerpc/64s: Use generic permission masks
  2023-09-25 18:31 [PATCH v2 00/37] Implement execute-only protection on powerpc Christophe Leroy
                   ` (25 preceding siblings ...)
  2023-09-25 18:31 ` [PATCH v2 26/37] powerpc/8xx: Use generic permission masks Christophe Leroy
@ 2023-09-25 18:31 ` Christophe Leroy
  2023-09-25 18:31 ` [PATCH v2 28/37] powerpc/nohash: Add _PAGE_WRITE to supplement _PAGE_RW Christophe Leroy
                   ` (11 subsequent siblings)
  38 siblings, 0 replies; 50+ messages in thread
From: Christophe Leroy @ 2023-09-25 18:31 UTC (permalink / raw)
  To: Michael Ellerman, Nicholas Piggin; +Cc: linuxppc-dev, linux-kernel

book3s64 need specific masks because it needs _PAGE_PRIVILEGED
for PAGE_NONE.

book3s64 already has _PAGE_RW and _PAGE_RWX.
So add _PAGE_NA, _PAGE_RO and _PAGE_ROX and remove specific
permission masks.

Signed-off-by: Christophe Leroy <christophe.leroy@csgroup.eu>
---
Not sure why it needs _PAGE_PRIVILEGED as it also have _PAGE_READ
and _PAGE_READ is not set on PAGE_NONE.
---
 arch/powerpc/include/asm/book3s/64/pgtable.h | 20 +++++---------------
 1 file changed, 5 insertions(+), 15 deletions(-)

diff --git a/arch/powerpc/include/asm/book3s/64/pgtable.h b/arch/powerpc/include/asm/book3s/64/pgtable.h
index c3b921769ece..0fd12bdc7b5e 100644
--- a/arch/powerpc/include/asm/book3s/64/pgtable.h
+++ b/arch/powerpc/include/asm/book3s/64/pgtable.h
@@ -17,6 +17,9 @@
 #define _PAGE_EXEC		0x00001 /* execute permission */
 #define _PAGE_WRITE		0x00002 /* write access allowed */
 #define _PAGE_READ		0x00004	/* read access allowed */
+#define _PAGE_NA		_PAGE_PRIVILEGED
+#define _PAGE_RO		_PAGE_READ
+#define _PAGE_ROX		(_PAGE_READ | _PAGE_EXEC)
 #define _PAGE_RW		(_PAGE_READ | _PAGE_WRITE)
 #define _PAGE_RWX		(_PAGE_READ | _PAGE_WRITE | _PAGE_EXEC)
 #define _PAGE_PRIVILEGED	0x00008 /* kernel access only */
@@ -136,21 +139,8 @@
 #define _PAGE_BASE_NC	(_PAGE_PRESENT | _PAGE_ACCESSED)
 #define _PAGE_BASE	(_PAGE_BASE_NC)
 
-/* Permission masks used to generate the __P and __S table,
- *
- * Note:__pgprot is defined in arch/powerpc/include/asm/page.h
- *
- * Write permissions imply read permissions for now (we could make write-only
- * pages on BookE but we don't bother for now). Execute permission control is
- * possible on platforms that define _PAGE_EXEC
- */
-#define PAGE_NONE	__pgprot(_PAGE_BASE | _PAGE_PRIVILEGED)
-#define PAGE_SHARED	__pgprot(_PAGE_BASE | _PAGE_RW)
-#define PAGE_SHARED_X	__pgprot(_PAGE_BASE | _PAGE_RW | _PAGE_EXEC)
-#define PAGE_COPY	__pgprot(_PAGE_BASE | _PAGE_READ)
-#define PAGE_COPY_X	__pgprot(_PAGE_BASE | _PAGE_READ | _PAGE_EXEC)
-#define PAGE_READONLY	__pgprot(_PAGE_BASE | _PAGE_READ)
-#define PAGE_READONLY_X	__pgprot(_PAGE_BASE | _PAGE_READ | _PAGE_EXEC)
+#include <asm/pgtable-masks.h>
+
 /* Radix only, Hash uses PAGE_READONLY_X + execute-only pkey instead */
 #define PAGE_EXECONLY	__pgprot(_PAGE_BASE | _PAGE_EXEC)
 
-- 
2.41.0


^ permalink raw reply related	[flat|nested] 50+ messages in thread

* [PATCH v2 28/37] powerpc/nohash: Add _PAGE_WRITE to supplement _PAGE_RW
  2023-09-25 18:31 [PATCH v2 00/37] Implement execute-only protection on powerpc Christophe Leroy
                   ` (26 preceding siblings ...)
  2023-09-25 18:31 ` [PATCH v2 27/37] powerpc/64s: " Christophe Leroy
@ 2023-09-25 18:31 ` Christophe Leroy
  2023-09-25 18:31 ` [PATCH v2 29/37] powerpc/nohash: Replace pte_user() by pte_read() Christophe Leroy
                   ` (10 subsequent siblings)
  38 siblings, 0 replies; 50+ messages in thread
From: Christophe Leroy @ 2023-09-25 18:31 UTC (permalink / raw)
  To: Michael Ellerman, Nicholas Piggin; +Cc: linuxppc-dev, linux-kernel

Several places, _PAGE_RW maps to write permission and don't
always imply read. To make it more clear, do as book3s/64 in
commit c7d54842deb1 ("powerpc/mm: Use _PAGE_READ to indicate
Read access") and use _PAGE_WRITE when more relevant.

For the time being _PAGE_WRITE is equivalent to _PAGE_RW but that
will change when _PAGE_READ gets added in following patches.

Signed-off-by: Christophe Leroy <christophe.leroy@csgroup.eu>
---
 arch/powerpc/include/asm/nohash/32/pte-40x.h  |  2 ++
 arch/powerpc/include/asm/nohash/32/pte-44x.h  |  2 ++
 arch/powerpc/include/asm/nohash/32/pte-85xx.h |  2 ++
 arch/powerpc/include/asm/nohash/64/pgtable.h  |  2 +-
 arch/powerpc/include/asm/nohash/pgtable.h     |  9 ++++++---
 arch/powerpc/include/asm/nohash/pte-e500.h    |  2 ++
 arch/powerpc/kernel/head_40x.S                | 12 ++++++------
 arch/powerpc/kernel/head_44x.S                |  4 ++--
 arch/powerpc/kernel/head_85xx.S               |  2 +-
 arch/powerpc/mm/nohash/e500.c                 |  4 ++--
 10 files changed, 26 insertions(+), 15 deletions(-)

diff --git a/arch/powerpc/include/asm/nohash/32/pte-40x.h b/arch/powerpc/include/asm/nohash/32/pte-40x.h
index 0b4e5f8ce3e8..e28ef0f5781e 100644
--- a/arch/powerpc/include/asm/nohash/32/pte-40x.h
+++ b/arch/powerpc/include/asm/nohash/32/pte-40x.h
@@ -49,6 +49,8 @@
 #define _PAGE_EXEC	0x200	/* hardware: EX permission */
 #define _PAGE_ACCESSED	0x400	/* software: R: page referenced */
 
+#define _PAGE_WRITE	_PAGE_RW
+
 /* No page size encoding in the linux PTE */
 #define _PAGE_PSIZE		0
 
diff --git a/arch/powerpc/include/asm/nohash/32/pte-44x.h b/arch/powerpc/include/asm/nohash/32/pte-44x.h
index b7ed13cee137..fc0c075006ea 100644
--- a/arch/powerpc/include/asm/nohash/32/pte-44x.h
+++ b/arch/powerpc/include/asm/nohash/32/pte-44x.h
@@ -75,6 +75,8 @@
 #define _PAGE_NO_CACHE	0x00000400		/* H: I bit */
 #define _PAGE_WRITETHRU	0x00000800		/* H: W bit */
 
+#define _PAGE_WRITE	_PAGE_RW
+
 /* No page size encoding in the linux PTE */
 #define _PAGE_PSIZE		0
 
diff --git a/arch/powerpc/include/asm/nohash/32/pte-85xx.h b/arch/powerpc/include/asm/nohash/32/pte-85xx.h
index 16451df5ddb0..462acf69e302 100644
--- a/arch/powerpc/include/asm/nohash/32/pte-85xx.h
+++ b/arch/powerpc/include/asm/nohash/32/pte-85xx.h
@@ -31,6 +31,8 @@
 #define _PAGE_WRITETHRU	0x00400	/* H: W bit */
 #define _PAGE_SPECIAL	0x00800 /* S: Special page */
 
+#define _PAGE_WRITE	_PAGE_RW
+
 #define _PAGE_KERNEL_RO		0
 #define _PAGE_KERNEL_ROX	_PAGE_EXEC
 #define _PAGE_KERNEL_RW		(_PAGE_DIRTY | _PAGE_RW)
diff --git a/arch/powerpc/include/asm/nohash/64/pgtable.h b/arch/powerpc/include/asm/nohash/64/pgtable.h
index 36b9bad428cc..2202c78730e8 100644
--- a/arch/powerpc/include/asm/nohash/64/pgtable.h
+++ b/arch/powerpc/include/asm/nohash/64/pgtable.h
@@ -149,7 +149,7 @@ static inline void p4d_set(p4d_t *p4dp, unsigned long val)
 static inline void huge_ptep_set_wrprotect(struct mm_struct *mm,
 					   unsigned long addr, pte_t *ptep)
 {
-	pte_update(mm, addr, ptep, _PAGE_RW, 0, 1);
+	pte_update(mm, addr, ptep, _PAGE_WRITE, 0, 1);
 }
 
 #define __HAVE_ARCH_PTEP_CLEAR_YOUNG_FLUSH
diff --git a/arch/powerpc/include/asm/nohash/pgtable.h b/arch/powerpc/include/asm/nohash/pgtable.h
index 200f2dbf48e2..ee677162f9e6 100644
--- a/arch/powerpc/include/asm/nohash/pgtable.h
+++ b/arch/powerpc/include/asm/nohash/pgtable.h
@@ -84,7 +84,7 @@ static inline int ptep_test_and_clear_young(struct vm_area_struct *vma,
 static inline void ptep_set_wrprotect(struct mm_struct *mm, unsigned long addr,
 				      pte_t *ptep)
 {
-	pte_update(mm, addr, ptep, _PAGE_RW, 0, 0);
+	pte_update(mm, addr, ptep, _PAGE_WRITE, 0, 0);
 }
 #endif
 #define __HAVE_ARCH_PTEP_SET_WRPROTECT
@@ -123,6 +123,9 @@ static inline void __ptep_set_access_flags(struct vm_area_struct *vma,
 #ifndef pte_mkwrite_novma
 static inline pte_t pte_mkwrite_novma(pte_t pte)
 {
+	/*
+	 * write implies read, hence set both
+	 */
 	return __pte(pte_val(pte) | _PAGE_RW);
 }
 #endif
@@ -140,7 +143,7 @@ static inline pte_t pte_mkyoung(pte_t pte)
 #ifndef pte_wrprotect
 static inline pte_t pte_wrprotect(pte_t pte)
 {
-	return __pte(pte_val(pte) & ~_PAGE_RW);
+	return __pte(pte_val(pte) & ~_PAGE_WRITE);
 }
 #endif
 
@@ -154,7 +157,7 @@ static inline pte_t pte_mkexec(pte_t pte)
 #ifndef pte_write
 static inline int pte_write(pte_t pte)
 {
-	return pte_val(pte) & _PAGE_RW;
+	return pte_val(pte) & _PAGE_WRITE;
 }
 #endif
 #ifndef pte_read
diff --git a/arch/powerpc/include/asm/nohash/pte-e500.h b/arch/powerpc/include/asm/nohash/pte-e500.h
index 9f9e3f02d414..b775c7d465a4 100644
--- a/arch/powerpc/include/asm/nohash/pte-e500.h
+++ b/arch/powerpc/include/asm/nohash/pte-e500.h
@@ -55,6 +55,8 @@
 #define _PAGE_KERNEL_ROX	(_PAGE_BAP_SR | _PAGE_BAP_SX)
 #define _PAGE_USER		(_PAGE_BAP_UR | _PAGE_BAP_SR) /* Can be read */
 
+#define _PAGE_WRITE	_PAGE_RW
+
 #define _PAGE_SPECIAL	_PAGE_SW0
 
 /* Base page size */
diff --git a/arch/powerpc/kernel/head_40x.S b/arch/powerpc/kernel/head_40x.S
index b32e7b2ebdcf..9f92f5c5e6aa 100644
--- a/arch/powerpc/kernel/head_40x.S
+++ b/arch/powerpc/kernel/head_40x.S
@@ -316,9 +316,9 @@ _ASM_NOKPROBE_SYMBOL(\name\()_virt)
 	andc.	r9, r9, r11		/* Check permission */
 	bne	5f
 
-	rlwinm	r9, r11, 1, _PAGE_RW	/* dirty => rw */
-	and	r9, r9, r11		/* hwwrite = dirty & rw */
-	rlwimi	r11, r9, 0, _PAGE_RW	/* replace rw by hwwrite */
+	rlwinm	r9, r11, 1, _PAGE_WRITE	/* dirty => w */
+	and	r9, r9, r11		/* hwwrite = dirty & w */
+	rlwimi	r11, r9, 0, _PAGE_WRITE	/* replace w by hwwrite */
 
 	/* Create TLB tag.  This is the faulting address plus a static
 	 * set of bits.  These are size, valid, E, U0.
@@ -400,9 +400,9 @@ _ASM_NOKPROBE_SYMBOL(\name\()_virt)
 	andc.	r9, r9, r11		/* Check permission */
 	bne	5f
 
-	rlwinm	r9, r11, 1, _PAGE_RW	/* dirty => rw */
-	and	r9, r9, r11		/* hwwrite = dirty & rw */
-	rlwimi	r11, r9, 0, _PAGE_RW	/* replace rw by hwwrite */
+	rlwinm	r9, r11, 1, _PAGE_WRITE	/* dirty => w */
+	and	r9, r9, r11		/* hwwrite = dirty & w */
+	rlwimi	r11, r9, 0, _PAGE_WRITE	/* replace w by hwwrite */
 
 	/* Create TLB tag.  This is the faulting address plus a static
 	 * set of bits.  These are size, valid, E, U0.
diff --git a/arch/powerpc/kernel/head_44x.S b/arch/powerpc/kernel/head_44x.S
index a3197c9f721c..858dabf84432 100644
--- a/arch/powerpc/kernel/head_44x.S
+++ b/arch/powerpc/kernel/head_44x.S
@@ -342,7 +342,7 @@ interrupt_base:
 	mtspr	SPRN_MMUCR,r12
 
 	/* Mask of required permission bits. Note that while we
-	 * do copy ESR:ST to _PAGE_RW position as trying to write
+	 * do copy ESR:ST to _PAGE_WRITE position as trying to write
 	 * to an RO page is pretty common, we don't do it with
 	 * _PAGE_DIRTY. We could do it, but it's a fairly rare
 	 * event so I'd rather take the overhead when it happens
@@ -586,7 +586,7 @@ finish_tlb_load_44x:
 4:	mtspr	SPRN_MMUCR,r12		/* Set MMUCR */
 
 	/* Mask of required permission bits. Note that while we
-	 * do copy ESR:ST to _PAGE_RW position as trying to write
+	 * do copy ESR:ST to _PAGE_WRITE position as trying to write
 	 * to an RO page is pretty common, we don't do it with
 	 * _PAGE_DIRTY. We could do it, but it's a fairly rare
 	 * event so I'd rather take the overhead when it happens
diff --git a/arch/powerpc/kernel/head_85xx.S b/arch/powerpc/kernel/head_85xx.S
index 97e9ea0c7297..594756a62c8e 100644
--- a/arch/powerpc/kernel/head_85xx.S
+++ b/arch/powerpc/kernel/head_85xx.S
@@ -471,7 +471,7 @@ END_BTB_FLUSH_SECTION
 
 4:
 	/* Mask of required permission bits. Note that while we
-	 * do copy ESR:ST to _PAGE_RW position as trying to write
+	 * do copy ESR:ST to _PAGE_WRITE position as trying to write
 	 * to an RO page is pretty common, we don't do it with
 	 * _PAGE_DIRTY. We could do it, but it's a fairly rare
 	 * event so I'd rather take the overhead when it happens
diff --git a/arch/powerpc/mm/nohash/e500.c b/arch/powerpc/mm/nohash/e500.c
index 5b7d7a932bfd..921c3521ec11 100644
--- a/arch/powerpc/mm/nohash/e500.c
+++ b/arch/powerpc/mm/nohash/e500.c
@@ -117,7 +117,7 @@ static void settlbcam(int index, unsigned long virt, phys_addr_t phys,
 	TLBCAM[index].MAS2 |= (flags & _PAGE_ENDIAN) ? MAS2_E : 0;
 
 	TLBCAM[index].MAS3 = (phys & MAS3_RPN) | MAS3_SR;
-	TLBCAM[index].MAS3 |= (flags & _PAGE_RW) ? MAS3_SW : 0;
+	TLBCAM[index].MAS3 |= (flags & _PAGE_WRITE) ? MAS3_SW : 0;
 	if (mmu_has_feature(MMU_FTR_BIG_PHYS))
 		TLBCAM[index].MAS7 = (u64)phys >> 32;
 
@@ -125,7 +125,7 @@ static void settlbcam(int index, unsigned long virt, phys_addr_t phys,
 	if (!is_kernel_addr(virt)) {
 		TLBCAM[index].MAS3 |= MAS3_UR;
 		TLBCAM[index].MAS3 |= (flags & _PAGE_EXEC) ? MAS3_UX : 0;
-		TLBCAM[index].MAS3 |= (flags & _PAGE_RW) ? MAS3_UW : 0;
+		TLBCAM[index].MAS3 |= (flags & _PAGE_WRITE) ? MAS3_UW : 0;
 	} else {
 		TLBCAM[index].MAS3 |= (flags & _PAGE_EXEC) ? MAS3_SX : 0;
 	}
-- 
2.41.0


^ permalink raw reply related	[flat|nested] 50+ messages in thread

* [PATCH v2 29/37] powerpc/nohash: Replace pte_user() by pte_read()
  2023-09-25 18:31 [PATCH v2 00/37] Implement execute-only protection on powerpc Christophe Leroy
                   ` (27 preceding siblings ...)
  2023-09-25 18:31 ` [PATCH v2 28/37] powerpc/nohash: Add _PAGE_WRITE to supplement _PAGE_RW Christophe Leroy
@ 2023-09-25 18:31 ` Christophe Leroy
  2023-10-31 10:15   ` Aneesh Kumar K.V
  2023-09-25 18:31 ` [PATCH v2 30/37] powerpc/e500: Introduce _PAGE_READ and remove _PAGE_USER Christophe Leroy
                   ` (9 subsequent siblings)
  38 siblings, 1 reply; 50+ messages in thread
From: Christophe Leroy @ 2023-09-25 18:31 UTC (permalink / raw)
  To: Michael Ellerman, Nicholas Piggin; +Cc: linuxppc-dev, linux-kernel

pte_user() is now only used in pte_access_permitted() to check
access on vmas. User flag is cleared to make a page unreadable.

So rename it pte_read() and remove pte_user() which isn't used
anymore.

For the time being it checks _PAGE_USER but in the near futur
all plateforms will be converted to _PAGE_READ so lets support
both for now.

Signed-off-by: Christophe Leroy <christophe.leroy@csgroup.eu>
---
 arch/powerpc/include/asm/nohash/32/pte-8xx.h |  7 -------
 arch/powerpc/include/asm/nohash/pgtable.h    | 13 +++++++------
 arch/powerpc/mm/ioremap.c                    |  4 ----
 3 files changed, 7 insertions(+), 17 deletions(-)

diff --git a/arch/powerpc/include/asm/nohash/32/pte-8xx.h b/arch/powerpc/include/asm/nohash/32/pte-8xx.h
index 62c965a4511a..1ee38befd29a 100644
--- a/arch/powerpc/include/asm/nohash/32/pte-8xx.h
+++ b/arch/powerpc/include/asm/nohash/32/pte-8xx.h
@@ -112,13 +112,6 @@ static inline pte_t pte_mkwrite_novma(pte_t pte)
 
 #define pte_mkwrite_novma pte_mkwrite_novma
 
-static inline bool pte_user(pte_t pte)
-{
-	return !(pte_val(pte) & _PAGE_SH);
-}
-
-#define pte_user pte_user
-
 static inline pte_t pte_mkhuge(pte_t pte)
 {
 	return __pte(pte_val(pte) | _PAGE_SPS | _PAGE_HUGE);
diff --git a/arch/powerpc/include/asm/nohash/pgtable.h b/arch/powerpc/include/asm/nohash/pgtable.h
index ee677162f9e6..aba56fe3b1c6 100644
--- a/arch/powerpc/include/asm/nohash/pgtable.h
+++ b/arch/powerpc/include/asm/nohash/pgtable.h
@@ -160,9 +160,6 @@ static inline int pte_write(pte_t pte)
 	return pte_val(pte) & _PAGE_WRITE;
 }
 #endif
-#ifndef pte_read
-static inline int pte_read(pte_t pte)		{ return 1; }
-#endif
 static inline int pte_dirty(pte_t pte)		{ return pte_val(pte) & _PAGE_DIRTY; }
 static inline int pte_special(pte_t pte)	{ return pte_val(pte) & _PAGE_SPECIAL; }
 static inline int pte_none(pte_t pte)		{ return (pte_val(pte) & ~_PTE_NONE_MASK) == 0; }
@@ -190,10 +187,14 @@ static inline int pte_young(pte_t pte)
  * and PTE_64BIT, PAGE_KERNEL_X contains _PAGE_BAP_SR which is also in
  * _PAGE_USER.  Need to explicitly match _PAGE_BAP_UR bit in that case too.
  */
-#ifndef pte_user
-static inline bool pte_user(pte_t pte)
+#ifndef pte_read
+static inline bool pte_read(pte_t pte)
 {
+#ifdef _PAGE_READ
+	return (pte_val(pte) & _PAGE_READ) == _PAGE_READ;
+#else
 	return (pte_val(pte) & _PAGE_USER) == _PAGE_USER;
+#endif
 }
 #endif
 
@@ -208,7 +209,7 @@ static inline bool pte_access_permitted(pte_t pte, bool write)
 	 * A read-only access is controlled by _PAGE_USER bit.
 	 * We have _PAGE_READ set for WRITE and EXECUTE
 	 */
-	if (!pte_present(pte) || !pte_user(pte) || !pte_read(pte))
+	if (!pte_present(pte) || !pte_read(pte))
 		return false;
 
 	if (write && !pte_write(pte))
diff --git a/arch/powerpc/mm/ioremap.c b/arch/powerpc/mm/ioremap.c
index 7823c38f09de..7b0afcabd89f 100644
--- a/arch/powerpc/mm/ioremap.c
+++ b/arch/powerpc/mm/ioremap.c
@@ -50,10 +50,6 @@ void __iomem *ioremap_prot(phys_addr_t addr, size_t size, unsigned long flags)
 	if (pte_write(pte))
 		pte = pte_mkdirty(pte);
 
-	/* we don't want to let _PAGE_USER leak out */
-	if (WARN_ON(pte_user(pte)))
-		return NULL;
-
 	if (iowa_is_active())
 		return iowa_ioremap(addr, size, pte_pgprot(pte), caller);
 	return __ioremap_caller(addr, size, pte_pgprot(pte), caller);
-- 
2.41.0


^ permalink raw reply related	[flat|nested] 50+ messages in thread

* [PATCH v2 30/37] powerpc/e500: Introduce _PAGE_READ and remove _PAGE_USER
  2023-09-25 18:31 [PATCH v2 00/37] Implement execute-only protection on powerpc Christophe Leroy
                   ` (28 preceding siblings ...)
  2023-09-25 18:31 ` [PATCH v2 29/37] powerpc/nohash: Replace pte_user() by pte_read() Christophe Leroy
@ 2023-09-25 18:31 ` Christophe Leroy
  2023-09-25 18:31 ` [PATCH v2 31/37] powerpc/44x: " Christophe Leroy
                   ` (8 subsequent siblings)
  38 siblings, 0 replies; 50+ messages in thread
From: Christophe Leroy @ 2023-09-25 18:31 UTC (permalink / raw)
  To: Michael Ellerman, Nicholas Piggin; +Cc: linuxppc-dev, linux-kernel

e500 MMU has 6 page protection bits:
- R, W, X for supervisor
- R, W, X for user

It means that it can support X without R.

To do that, _PAGE_READ flag is needed.

With 32 bits PTE there is no bit available for it in PTE. On the
other hand the only real use of _PAGE_USER is to implement PAGE_NONE
by clearing _PAGE_USER. As _PAGE_NONE can also be implemented by
clearing _PAGE_READ, remove _PAGE_USER and add _PAGE_READ. Move
_PAGE_PRESENT into bit 30 so that _PAGE_READ can match SR bit.

With 64 bits PTE _PAGE_USER is already the combination of SR and UR
so all we need to do is to rename it _PAGE_READ.

Signed-off-by: Christophe Leroy <christophe.leroy@csgroup.eu>
---
 arch/powerpc/include/asm/nohash/32/pte-85xx.h | 22 ++++---------------
 arch/powerpc/include/asm/nohash/pte-e500.h    | 20 ++++++++---------
 arch/powerpc/kernel/head_85xx.S               | 10 ++++-----
 3 files changed, 18 insertions(+), 34 deletions(-)

diff --git a/arch/powerpc/include/asm/nohash/32/pte-85xx.h b/arch/powerpc/include/asm/nohash/32/pte-85xx.h
index 462acf69e302..653a342d3b25 100644
--- a/arch/powerpc/include/asm/nohash/32/pte-85xx.h
+++ b/arch/powerpc/include/asm/nohash/32/pte-85xx.h
@@ -17,9 +17,9 @@
 */
 
 /* Definitions for FSL Book-E Cores */
-#define _PAGE_PRESENT	0x00001	/* S: PTE contains a translation */
-#define _PAGE_USER	0x00002	/* S: User page (maps to UR) */
-#define _PAGE_RW	0x00004	/* S: Write permission (SW) */
+#define _PAGE_READ	0x00001	/* H: Read permission (SR) */
+#define _PAGE_PRESENT	0x00002	/* S: PTE contains a translation */
+#define _PAGE_WRITE	0x00004	/* S: Write permission (SW) */
 #define _PAGE_DIRTY	0x00008	/* S: Page dirty */
 #define _PAGE_EXEC	0x00010	/* H: SX permission */
 #define _PAGE_ACCESSED	0x00020	/* S: Page referenced */
@@ -31,13 +31,6 @@
 #define _PAGE_WRITETHRU	0x00400	/* H: W bit */
 #define _PAGE_SPECIAL	0x00800 /* S: Special page */
 
-#define _PAGE_WRITE	_PAGE_RW
-
-#define _PAGE_KERNEL_RO		0
-#define _PAGE_KERNEL_ROX	_PAGE_EXEC
-#define _PAGE_KERNEL_RW		(_PAGE_DIRTY | _PAGE_RW)
-#define _PAGE_KERNEL_RWX	(_PAGE_DIRTY | _PAGE_RW | _PAGE_EXEC)
-
 /* No page size encoding in the linux PTE */
 #define _PAGE_PSIZE		0
 
@@ -63,14 +56,7 @@
 #define _PAGE_BASE	(_PAGE_BASE_NC)
 #endif
 
-/* Permission masks used to generate the __P and __S table */
-#define PAGE_NONE	__pgprot(_PAGE_BASE)
-#define PAGE_SHARED	__pgprot(_PAGE_BASE | _PAGE_USER | _PAGE_RW)
-#define PAGE_SHARED_X	__pgprot(_PAGE_BASE | _PAGE_USER | _PAGE_RW | _PAGE_EXEC)
-#define PAGE_COPY	__pgprot(_PAGE_BASE | _PAGE_USER)
-#define PAGE_COPY_X	__pgprot(_PAGE_BASE | _PAGE_USER | _PAGE_EXEC)
-#define PAGE_READONLY	__pgprot(_PAGE_BASE | _PAGE_USER)
-#define PAGE_READONLY_X	__pgprot(_PAGE_BASE | _PAGE_USER | _PAGE_EXEC)
+#include <asm/pgtable-masks.h>
 
 #endif /* __KERNEL__ */
 #endif /*  _ASM_POWERPC_NOHASH_32_PTE_FSL_85xx_H */
diff --git a/arch/powerpc/include/asm/nohash/pte-e500.h b/arch/powerpc/include/asm/nohash/pte-e500.h
index b775c7d465a4..31d2c3ea7df8 100644
--- a/arch/powerpc/include/asm/nohash/pte-e500.h
+++ b/arch/powerpc/include/asm/nohash/pte-e500.h
@@ -48,14 +48,19 @@
 
 /* "Higher level" linux bit combinations */
 #define _PAGE_EXEC		(_PAGE_BAP_SX | _PAGE_BAP_UX) /* .. and was cache cleaned */
-#define _PAGE_RW		(_PAGE_BAP_SW | _PAGE_BAP_UW) /* User write permission */
+#define _PAGE_READ		(_PAGE_BAP_SR | _PAGE_BAP_UR) /* User read permission */
+#define _PAGE_WRITE		(_PAGE_BAP_SW | _PAGE_BAP_UW) /* User write permission */
+
 #define _PAGE_KERNEL_RW		(_PAGE_BAP_SW | _PAGE_BAP_SR | _PAGE_DIRTY)
 #define _PAGE_KERNEL_RO		(_PAGE_BAP_SR)
 #define _PAGE_KERNEL_RWX	(_PAGE_BAP_SW | _PAGE_BAP_SR | _PAGE_DIRTY | _PAGE_BAP_SX)
 #define _PAGE_KERNEL_ROX	(_PAGE_BAP_SR | _PAGE_BAP_SX)
-#define _PAGE_USER		(_PAGE_BAP_UR | _PAGE_BAP_SR) /* Can be read */
 
-#define _PAGE_WRITE	_PAGE_RW
+#define _PAGE_NA	0
+#define _PAGE_RO	_PAGE_READ
+#define _PAGE_ROX	(_PAGE_READ | _PAGE_BAP_UX)
+#define _PAGE_RW	(_PAGE_READ | _PAGE_WRITE)
+#define _PAGE_RWX	(_PAGE_READ | _PAGE_WRITE | _PAGE_BAP_UX)
 
 #define _PAGE_SPECIAL	_PAGE_SW0
 
@@ -90,14 +95,7 @@
 #define _PAGE_BASE	(_PAGE_BASE_NC)
 #endif
 
-/* Permission masks used to generate the __P and __S table */
-#define PAGE_NONE	__pgprot(_PAGE_BASE)
-#define PAGE_SHARED	__pgprot(_PAGE_BASE | _PAGE_USER | _PAGE_RW)
-#define PAGE_SHARED_X	__pgprot(_PAGE_BASE | _PAGE_USER | _PAGE_RW | _PAGE_BAP_UX)
-#define PAGE_COPY	__pgprot(_PAGE_BASE | _PAGE_USER)
-#define PAGE_COPY_X	__pgprot(_PAGE_BASE | _PAGE_USER | _PAGE_BAP_UX)
-#define PAGE_READONLY	__pgprot(_PAGE_BASE | _PAGE_USER)
-#define PAGE_READONLY_X	__pgprot(_PAGE_BASE | _PAGE_USER | _PAGE_BAP_UX)
+#include <asm/pgtable-masks.h>
 
 #ifndef __ASSEMBLY__
 static inline pte_t pte_mkexec(pte_t pte)
diff --git a/arch/powerpc/kernel/head_85xx.S b/arch/powerpc/kernel/head_85xx.S
index 594756a62c8e..3739d5a281a7 100644
--- a/arch/powerpc/kernel/head_85xx.S
+++ b/arch/powerpc/kernel/head_85xx.S
@@ -485,10 +485,10 @@ END_BTB_FLUSH_SECTION
 	 */
 	mfspr	r12,SPRN_ESR
 #ifdef CONFIG_PTE_64BIT
-	li	r13,_PAGE_PRESENT
+	li	r13,_PAGE_PRESENT|_PAGE_BAP_SR
 	oris	r13,r13,_PAGE_ACCESSED@h
 #else
-	li	r13,_PAGE_PRESENT|_PAGE_ACCESSED
+	li	r13,_PAGE_PRESENT|_PAGE_READ|_PAGE_ACCESSED
 #endif
 	rlwimi	r13,r12,11,29,29
 
@@ -783,15 +783,15 @@ BEGIN_MMU_FTR_SECTION
 	mtspr	SPRN_MAS7, r10
 END_MMU_FTR_SECTION_IFSET(MMU_FTR_BIG_PHYS)
 #else
-	li	r10, (_PAGE_EXEC | _PAGE_PRESENT)
+	li	r10, (_PAGE_EXEC | _PAGE_READ)
 	mr	r13, r11
 	rlwimi	r10, r11, 31, 29, 29	/* extract _PAGE_DIRTY into SW */
 	and	r12, r11, r10
-	andi.	r10, r11, _PAGE_USER	/* Test for _PAGE_USER */
+	mcrf	cr0, cr5		/* Test for user page */
 	slwi	r10, r12, 1
 	or	r10, r10, r12
 	rlwinm	r10, r10, 0, ~_PAGE_EXEC	/* Clear SX on user pages */
-	iseleq	r12, r12, r10
+	isellt	r12, r10, r12
 	rlwimi	r13, r12, 0, 20, 31	/* Get RPN from PTE, merge w/ perms */
 	mtspr	SPRN_MAS3, r13
 #endif
-- 
2.41.0


^ permalink raw reply related	[flat|nested] 50+ messages in thread

* [PATCH v2 31/37] powerpc/44x: Introduce _PAGE_READ and remove _PAGE_USER
  2023-09-25 18:31 [PATCH v2 00/37] Implement execute-only protection on powerpc Christophe Leroy
                   ` (29 preceding siblings ...)
  2023-09-25 18:31 ` [PATCH v2 30/37] powerpc/e500: Introduce _PAGE_READ and remove _PAGE_USER Christophe Leroy
@ 2023-09-25 18:31 ` Christophe Leroy
  2023-09-25 18:31 ` [PATCH v2 32/37] powerpc/40x: " Christophe Leroy
                   ` (7 subsequent siblings)
  38 siblings, 0 replies; 50+ messages in thread
From: Christophe Leroy @ 2023-09-25 18:31 UTC (permalink / raw)
  To: Michael Ellerman, Nicholas Piggin; +Cc: linuxppc-dev, linux-kernel

44x MMU has 6 page protection bits:
- R, W, X for supervisor
- R, W, X for user

It means that it can support X without R.

To do that, _PAGE_READ flag is needed but there is no bit available
for it in PTE. On the other hand the only real use of _PAGE_USER is
to implement PAGE_NONE by clearing _PAGE_USER.

As _PAGE_NONE can also be implemented by clearing _PAGE_READ,
remove _PAGE_USER and add _PAGE_READ. In order to insert bits in
one go during TLB miss, move _PAGE_ACCESSED and put _PAGE_READ
just after _PAGE_DIRTY so that _PAGE_DIRTY is copied into SW and
_PAGE_READ into SR at once.

With that change, 44x now also honors execute-only protection.

Signed-off-by: Christophe Leroy <christophe.leroy@csgroup.eu>
---
 arch/powerpc/include/asm/nohash/32/pte-44x.h | 22 +++---------
 arch/powerpc/kernel/head_44x.S               | 36 ++++++++++----------
 2 files changed, 22 insertions(+), 36 deletions(-)

diff --git a/arch/powerpc/include/asm/nohash/32/pte-44x.h b/arch/powerpc/include/asm/nohash/32/pte-44x.h
index fc0c075006ea..851813725237 100644
--- a/arch/powerpc/include/asm/nohash/32/pte-44x.h
+++ b/arch/powerpc/include/asm/nohash/32/pte-44x.h
@@ -63,28 +63,21 @@
  */
 
 #define _PAGE_PRESENT	0x00000001		/* S: PTE valid */
-#define _PAGE_RW	0x00000002		/* S: Write permission */
+#define _PAGE_WRITE	0x00000002		/* S: Write permission */
 #define _PAGE_EXEC	0x00000004		/* H: Execute permission */
-#define _PAGE_ACCESSED	0x00000008		/* S: Page referenced */
+#define _PAGE_READ	0x00000008		/* S: Read permission */
 #define _PAGE_DIRTY	0x00000010		/* S: Page dirty */
 #define _PAGE_SPECIAL	0x00000020		/* S: Special page */
-#define _PAGE_USER	0x00000040		/* S: User page */
+#define _PAGE_ACCESSED	0x00000040		/* S: Page referenced */
 #define _PAGE_ENDIAN	0x00000080		/* H: E bit */
 #define _PAGE_GUARDED	0x00000100		/* H: G bit */
 #define _PAGE_COHERENT	0x00000200		/* H: M bit */
 #define _PAGE_NO_CACHE	0x00000400		/* H: I bit */
 #define _PAGE_WRITETHRU	0x00000800		/* H: W bit */
 
-#define _PAGE_WRITE	_PAGE_RW
-
 /* No page size encoding in the linux PTE */
 #define _PAGE_PSIZE		0
 
-#define _PAGE_KERNEL_RO		0
-#define _PAGE_KERNEL_ROX	_PAGE_EXEC
-#define _PAGE_KERNEL_RW		(_PAGE_DIRTY | _PAGE_RW)
-#define _PAGE_KERNEL_RWX	(_PAGE_DIRTY | _PAGE_RW | _PAGE_EXEC)
-
 /* TODO: Add large page lowmem mapping support */
 #define _PMD_PRESENT	0
 #define _PMD_PRESENT_MASK (PAGE_MASK)
@@ -107,14 +100,7 @@
 #define _PAGE_BASE	(_PAGE_BASE_NC)
 #endif
 
-/* Permission masks used to generate the __P and __S table */
-#define PAGE_NONE	__pgprot(_PAGE_BASE)
-#define PAGE_SHARED	__pgprot(_PAGE_BASE | _PAGE_USER | _PAGE_RW)
-#define PAGE_SHARED_X	__pgprot(_PAGE_BASE | _PAGE_USER | _PAGE_RW | _PAGE_EXEC)
-#define PAGE_COPY	__pgprot(_PAGE_BASE | _PAGE_USER)
-#define PAGE_COPY_X	__pgprot(_PAGE_BASE | _PAGE_USER | _PAGE_EXEC)
-#define PAGE_READONLY	__pgprot(_PAGE_BASE | _PAGE_USER)
-#define PAGE_READONLY_X	__pgprot(_PAGE_BASE | _PAGE_USER | _PAGE_EXEC)
+#include <asm/pgtable-masks.h>
 
 #endif /* __KERNEL__ */
 #endif /*  _ASM_POWERPC_NOHASH_32_PTE_44x_H */
diff --git a/arch/powerpc/kernel/head_44x.S b/arch/powerpc/kernel/head_44x.S
index 858dabf84432..25642e802ed3 100644
--- a/arch/powerpc/kernel/head_44x.S
+++ b/arch/powerpc/kernel/head_44x.S
@@ -314,8 +314,8 @@ interrupt_base:
 	 * kernel page tables.
 	 */
 	lis	r11, PAGE_OFFSET@h
-	cmplw	r10, r11
-	blt+	3f
+	cmplw	cr7, r10, r11
+	blt+	cr7, 3f
 	lis	r11, swapper_pg_dir@h
 	ori	r11, r11, swapper_pg_dir@l
 
@@ -355,7 +355,7 @@ interrupt_base:
 	 *       place or can we save a couple of instructions here ?
 	 */
 	mfspr	r12,SPRN_ESR
-	li	r13,_PAGE_PRESENT|_PAGE_ACCESSED
+	li	r13,_PAGE_PRESENT|_PAGE_ACCESSED|_PAGE_READ
 	rlwimi	r13,r12,10,30,30
 
 	/* Load the PTE */
@@ -428,8 +428,8 @@ interrupt_base:
 	 * kernel page tables.
 	 */
 	lis	r11, PAGE_OFFSET@h
-	cmplw	r10, r11
-	blt+	3f
+	cmplw	cr7, r10, r11
+	blt+	cr7, 3f
 	lis	r11, swapper_pg_dir@h
 	ori	r11, r11, swapper_pg_dir@l
 
@@ -515,6 +515,7 @@ interrupt_base:
  * 	r11 - PTE high word value
  *	r12 - PTE low word value
  *	r13 - TLB index
+ *	cr7 - Result of comparison with PAGE_OFFSET
  *	MMUCR - loaded with proper value when we get here
  *	Upon exit, we reload everything and RFI.
  */
@@ -533,11 +534,10 @@ finish_tlb_load_44x:
 	tlbwe	r10,r13,PPC44x_TLB_PAGEID	/* Write PAGEID */
 
 	/* And WS 2 */
-	li	r10,0xf85			/* Mask to apply from PTE */
-	rlwimi	r10,r12,29,30,30		/* DIRTY -> SW position */
+	li	r10,0xf84			/* Mask to apply from PTE */
+	rlwimi	r10,r12,29,30,31		/* DIRTY,READ -> SW,SR position */
 	and	r11,r12,r10			/* Mask PTE bits to keep */
-	andi.	r10,r12,_PAGE_USER		/* User page ? */
-	beq	1f				/* nope, leave U bits empty */
+	bge	cr7,1f			/* User page ? no, leave U bits empty */
 	rlwimi	r11,r11,3,26,28			/* yes, copy S bits to U */
 	rlwinm	r11,r11,0,~PPC44x_TLB_SX	/* Clear SX if User page */
 1:	tlbwe	r11,r13,PPC44x_TLB_ATTRIB	/* Write ATTRIB */
@@ -568,8 +568,8 @@ finish_tlb_load_44x:
 	 * kernel page tables.
 	 */
 	lis	r11,PAGE_OFFSET@h
-	cmplw	cr0,r10,r11
-	blt+	3f
+	cmplw	cr7,r10,r11
+	blt+	cr7,3f
 	lis	r11,swapper_pg_dir@h
 	ori	r11,r11, swapper_pg_dir@l
 	li	r12,0			/* MMUCR = 0 */
@@ -599,7 +599,7 @@ finish_tlb_load_44x:
 	 *       place or can we save a couple of instructions here ?
 	 */
 	mfspr	r12,SPRN_ESR
-	li	r13,_PAGE_PRESENT|_PAGE_ACCESSED
+	li	r13,_PAGE_PRESENT|_PAGE_ACCESSED|_PAGE_READ
 	rlwimi	r13,r12,10,30,30
 
 	/* Load the PTE */
@@ -669,8 +669,8 @@ finish_tlb_load_44x:
 	 * kernel page tables.
 	 */
 	lis	r11,PAGE_OFFSET@h
-	cmplw	cr0,r10,r11
-	blt+	3f
+	cmplw	cr7,r10,r11
+	blt+	cr7,3f
 	lis	r11,swapper_pg_dir@h
 	ori	r11,r11, swapper_pg_dir@l
 	li	r12,0			/* MMUCR = 0 */
@@ -744,6 +744,7 @@ finish_tlb_load_44x:
  * 	r11 - PTE high word value
  *	r12 - PTE low word value
  *      r13 - free to use
+ *	cr7 - Result of comparison with PAGE_OFFSET
  *	MMUCR - loaded with proper value when we get here
  *	Upon exit, we reload everything and RFI.
  */
@@ -753,11 +754,10 @@ finish_tlb_load_47x:
 	tlbwe	r11,r13,1
 
 	/* And make up word 2 */
-	li	r10,0xf85			/* Mask to apply from PTE */
-	rlwimi	r10,r12,29,30,30		/* DIRTY -> SW position */
+	li	r10,0xf84			/* Mask to apply from PTE */
+	rlwimi	r10,r12,29,30,31		/* DIRTY,READ -> SW,SR position */
 	and	r11,r12,r10			/* Mask PTE bits to keep */
-	andi.	r10,r12,_PAGE_USER		/* User page ? */
-	beq	1f				/* nope, leave U bits empty */
+	bge	cr7,1f			/* User page ? no, leave U bits empty */
 	rlwimi	r11,r11,3,26,28			/* yes, copy S bits to U */
 	rlwinm	r11,r11,0,~PPC47x_TLB2_SX	/* Clear SX if User page */
 1:	tlbwe	r11,r13,2
-- 
2.41.0


^ permalink raw reply related	[flat|nested] 50+ messages in thread

* [PATCH v2 32/37] powerpc/40x: Introduce _PAGE_READ and remove _PAGE_USER
  2023-09-25 18:31 [PATCH v2 00/37] Implement execute-only protection on powerpc Christophe Leroy
                   ` (30 preceding siblings ...)
  2023-09-25 18:31 ` [PATCH v2 31/37] powerpc/44x: " Christophe Leroy
@ 2023-09-25 18:31 ` Christophe Leroy
  2023-09-25 18:31 ` [PATCH v2 33/37] powerpc/32s: Add _PAGE_WRITE to supplement _PAGE_RW Christophe Leroy
                   ` (6 subsequent siblings)
  38 siblings, 0 replies; 50+ messages in thread
From: Christophe Leroy @ 2023-09-25 18:31 UTC (permalink / raw)
  To: Michael Ellerman, Nicholas Piggin; +Cc: linuxppc-dev, linux-kernel

_PAGE_USER is used to select the zone. Today zone 0 is kernel
and zone 1 is user.

To implement _PAGE_NONE, _PAGE_USER is cleared, leading to no access
for user but kernel still has access to the page so it's possible for
a user application to write in that page by using a kernel function
as trampoline.

What is really wanted is to have user rights on pages below TASK_SIZE
and no user rights on pages above TASK_SIZE. Use zones for that.
There are 16 zones so lets use the 4 upper address bits to set the
zone and declare zone rights based on TASK_SIZE.

Then drop _PAGE_USER and reuse it as _PAGE_READ that will be checked
in Data TLB miss handler. That will properly handle PAGE_NONE for
both kernel and user.

In addition, it partially implements execute-only right. The
implementation won't be complete because once a TLB has been loaded
via the Instruction TLB miss handler, it will be possible to read
the page. But at least it can't be read unless it is executed first.

Signed-off-by: Christophe Leroy <christophe.leroy@csgroup.eu>
---
 arch/powerpc/include/asm/nohash/32/pte-40x.h | 20 +++-----------------
 arch/powerpc/kernel/head_40x.S               |  7 ++++---
 arch/powerpc/mm/nohash/40x.c                 | 19 ++++++++++++-------
 3 files changed, 19 insertions(+), 27 deletions(-)

diff --git a/arch/powerpc/include/asm/nohash/32/pte-40x.h b/arch/powerpc/include/asm/nohash/32/pte-40x.h
index e28ef0f5781e..d759cfd74754 100644
--- a/arch/powerpc/include/asm/nohash/32/pte-40x.h
+++ b/arch/powerpc/include/asm/nohash/32/pte-40x.h
@@ -42,26 +42,19 @@
 #define _PAGE_PRESENT	0x002	/* software: PTE contains a translation */
 #define	_PAGE_NO_CACHE	0x004	/* I: caching is inhibited */
 #define	_PAGE_WRITETHRU	0x008	/* W: caching is write-through */
-#define	_PAGE_USER	0x010	/* matches one of the zone permission bits */
+#define	_PAGE_READ	0x010	/* software: read permission */
 #define	_PAGE_SPECIAL	0x020	/* software: Special page */
 #define	_PAGE_DIRTY	0x080	/* software: dirty page */
-#define _PAGE_RW	0x100	/* hardware: WR, anded with dirty in exception */
+#define _PAGE_WRITE	0x100	/* hardware: WR, anded with dirty in exception */
 #define _PAGE_EXEC	0x200	/* hardware: EX permission */
 #define _PAGE_ACCESSED	0x400	/* software: R: page referenced */
 
-#define _PAGE_WRITE	_PAGE_RW
-
 /* No page size encoding in the linux PTE */
 #define _PAGE_PSIZE		0
 
 /* cache related flags non existing on 40x */
 #define _PAGE_COHERENT	0
 
-#define _PAGE_KERNEL_RO		0
-#define _PAGE_KERNEL_ROX	_PAGE_EXEC
-#define _PAGE_KERNEL_RW		(_PAGE_DIRTY | _PAGE_RW)
-#define _PAGE_KERNEL_RWX	(_PAGE_DIRTY | _PAGE_RW | _PAGE_EXEC)
-
 #define _PMD_PRESENT	0x400	/* PMD points to page of PTEs */
 #define _PMD_PRESENT_MASK	_PMD_PRESENT
 #define _PMD_BAD	0x802
@@ -74,14 +67,7 @@
 #define _PAGE_BASE_NC	(_PAGE_PRESENT | _PAGE_ACCESSED)
 #define _PAGE_BASE	(_PAGE_BASE_NC)
 
-/* Permission masks used to generate the __P and __S table */
-#define PAGE_NONE	__pgprot(_PAGE_BASE)
-#define PAGE_SHARED	__pgprot(_PAGE_BASE | _PAGE_USER | _PAGE_RW)
-#define PAGE_SHARED_X	__pgprot(_PAGE_BASE | _PAGE_USER | _PAGE_RW | _PAGE_EXEC)
-#define PAGE_COPY	__pgprot(_PAGE_BASE | _PAGE_USER)
-#define PAGE_COPY_X	__pgprot(_PAGE_BASE | _PAGE_USER | _PAGE_EXEC)
-#define PAGE_READONLY	__pgprot(_PAGE_BASE | _PAGE_USER)
-#define PAGE_READONLY_X	__pgprot(_PAGE_BASE | _PAGE_USER | _PAGE_EXEC)
+#include <asm/pgtable-masks.h>
 
 #endif /* __KERNEL__ */
 #endif /*  _ASM_POWERPC_NOHASH_32_PTE_40x_H */
diff --git a/arch/powerpc/kernel/head_40x.S b/arch/powerpc/kernel/head_40x.S
index 9f92f5c5e6aa..9fc90410b385 100644
--- a/arch/powerpc/kernel/head_40x.S
+++ b/arch/powerpc/kernel/head_40x.S
@@ -312,7 +312,7 @@ _ASM_NOKPROBE_SYMBOL(\name\()_virt)
 
 	rlwimi	r11, r10, 22, 20, 29	/* Compute PTE address */
 	lwz	r11, 0(r11)		/* Get Linux PTE */
-	li	r9, _PAGE_PRESENT | _PAGE_ACCESSED
+	li	r9, _PAGE_PRESENT | _PAGE_ACCESSED | _PAGE_READ
 	andc.	r9, r9, r11		/* Check permission */
 	bne	5f
 
@@ -561,10 +561,11 @@ finish_tlb_load:
 	/*
 	 * Clear out the software-only bits in the PTE to generate the
 	 * TLB_DATA value.  These are the bottom 2 bits of the RPM, the
-	 * top 3 bits of the zone field, and M.
+	 * 4 bits of the zone field, and M.
 	 */
-	li	r9, 0x0ce2
+	li	r9, 0x0cf2
 	andc	r11, r11, r9
+	rlwimi	r11, r10, 8, 24, 27	/* Copy 4 upper address bit into zone */
 
 	/* load the next available TLB index. */
 	lwz	r9, tlb_4xx_index@l(0)
diff --git a/arch/powerpc/mm/nohash/40x.c b/arch/powerpc/mm/nohash/40x.c
index 3684d6e570fb..e835e80c09db 100644
--- a/arch/powerpc/mm/nohash/40x.c
+++ b/arch/powerpc/mm/nohash/40x.c
@@ -48,20 +48,25 @@
  */
 void __init MMU_init_hw(void)
 {
+	int i;
+	unsigned long zpr;
+
 	/*
 	 * The Zone Protection Register (ZPR) defines how protection will
-	 * be applied to every page which is a member of a given zone. At
-	 * present, we utilize only two of the 4xx's zones.
+	 * be applied to every page which is a member of a given zone.
 	 * The zone index bits (of ZSEL) in the PTE are used for software
-	 * indicators, except the LSB.  For user access, zone 1 is used,
-	 * for kernel access, zone 0 is used.  We set all but zone 1
-	 * to zero, allowing only kernel access as indicated in the PTE.
-	 * For zone 1, we set a 01 binary (a value of 10 will not work)
+	 * indicators. We use the 4 upper bits of virtual address to select
+	 * the zone. We set all zones above TASK_SIZE to zero, allowing
+	 * only kernel access as indicated in the PTE. For zones below
+	 * TASK_SIZE, we set a 01 binary (a value of 10 will not work)
 	 * to allow user access as indicated in the PTE.  This also allows
 	 * kernel access as indicated in the PTE.
 	 */
 
-        mtspr(SPRN_ZPR, 0x10000000);
+	for (i = 0, zpr = 0; i < TASK_SIZE >> 28; i++)
+		zpr |= 1 << (30 - i * 2);
+
+	mtspr(SPRN_ZPR, zpr);
 
 	flush_instruction_cache();
 
-- 
2.41.0


^ permalink raw reply related	[flat|nested] 50+ messages in thread

* [PATCH v2 33/37] powerpc/32s: Add _PAGE_WRITE to supplement _PAGE_RW
  2023-09-25 18:31 [PATCH v2 00/37] Implement execute-only protection on powerpc Christophe Leroy
                   ` (31 preceding siblings ...)
  2023-09-25 18:31 ` [PATCH v2 32/37] powerpc/40x: " Christophe Leroy
@ 2023-09-25 18:31 ` Christophe Leroy
  2023-09-25 18:31 ` [PATCH v2 34/37] powerpc/32s: Introduce _PAGE_READ and remove _PAGE_USER Christophe Leroy
                   ` (5 subsequent siblings)
  38 siblings, 0 replies; 50+ messages in thread
From: Christophe Leroy @ 2023-09-25 18:31 UTC (permalink / raw)
  To: Michael Ellerman, Nicholas Piggin; +Cc: linuxppc-dev, linux-kernel

Several places, _PAGE_RW maps to write permission and don't
always imply read. To make it more clear, do as book3s/64 in
commit c7d54842deb1 ("powerpc/mm: Use _PAGE_READ to indicate
Read access") and use _PAGE_WRITE when more relevant.

For the time being _PAGE_WRITE is equivalent to _PAGE_RW but that
will change when _PAGE_READ gets added in following patches.

Signed-off-by: Christophe Leroy <christophe.leroy@csgroup.eu>
---
 arch/powerpc/include/asm/book3s/32/pgtable.h | 15 ++++++++++++---
 arch/powerpc/kernel/head_book3s_32.S         |  6 +++---
 arch/powerpc/mm/book3s32/hash_low.S          | 12 ++++++------
 arch/powerpc/mm/book3s32/mmu.c               |  2 +-
 4 files changed, 22 insertions(+), 13 deletions(-)

diff --git a/arch/powerpc/include/asm/book3s/32/pgtable.h b/arch/powerpc/include/asm/book3s/32/pgtable.h
index 80505915c77c..480ad6b4fd6f 100644
--- a/arch/powerpc/include/asm/book3s/32/pgtable.h
+++ b/arch/powerpc/include/asm/book3s/32/pgtable.h
@@ -31,6 +31,8 @@
 #define _PAGE_RW	0x400	/* software: user write access allowed */
 #define _PAGE_SPECIAL	0x800	/* software: Special page */
 
+#define _PAGE_WRITE	_PAGE_RW
+
 #ifdef CONFIG_PTE_64BIT
 /* We never clear the high word of the pte */
 #define _PTE_NONE_MASK	(0xffffffff00000000ULL | _PAGE_HASHPTE)
@@ -347,7 +349,7 @@ static inline pte_t ptep_get_and_clear(struct mm_struct *mm, unsigned long addr,
 static inline void ptep_set_wrprotect(struct mm_struct *mm, unsigned long addr,
 				      pte_t *ptep)
 {
-	pte_update(mm, addr, ptep, _PAGE_RW, 0, 0);
+	pte_update(mm, addr, ptep, _PAGE_WRITE, 0, 0);
 }
 
 static inline void __ptep_set_access_flags(struct vm_area_struct *vma,
@@ -406,7 +408,11 @@ static inline pte_t pte_swp_clear_exclusive(pte_t pte)
 }
 
 /* Generic accessors to PTE bits */
-static inline int pte_write(pte_t pte)		{ return !!(pte_val(pte) & _PAGE_RW);}
+static inline bool pte_write(pte_t pte)
+{
+	return !!(pte_val(pte) & _PAGE_WRITE);
+}
+
 static inline int pte_read(pte_t pte)		{ return 1; }
 static inline int pte_dirty(pte_t pte)		{ return !!(pte_val(pte) & _PAGE_DIRTY); }
 static inline int pte_young(pte_t pte)		{ return !!(pte_val(pte) & _PAGE_ACCESSED); }
@@ -469,7 +475,7 @@ static inline pte_t pfn_pte(unsigned long pfn, pgprot_t pgprot)
 /* Generic modifiers for PTE bits */
 static inline pte_t pte_wrprotect(pte_t pte)
 {
-	return __pte(pte_val(pte) & ~_PAGE_RW);
+	return __pte(pte_val(pte) & ~_PAGE_WRITE);
 }
 
 static inline pte_t pte_exprotect(pte_t pte)
@@ -499,6 +505,9 @@ static inline pte_t pte_mkpte(pte_t pte)
 
 static inline pte_t pte_mkwrite_novma(pte_t pte)
 {
+	/*
+	 * write implies read, hence set both
+	 */
 	return __pte(pte_val(pte) | _PAGE_RW);
 }
 
diff --git a/arch/powerpc/kernel/head_book3s_32.S b/arch/powerpc/kernel/head_book3s_32.S
index 6764b98ca360..615d429d7bd1 100644
--- a/arch/powerpc/kernel/head_book3s_32.S
+++ b/arch/powerpc/kernel/head_book3s_32.S
@@ -503,9 +503,9 @@ DataLoadTLBMiss:
 	andc.	r1,r1,r0		/* check access & ~permission */
 	bne-	DataAddressInvalid	/* return if access not permitted */
 	/* Convert linux-style PTE to low word of PPC-style PTE */
-	rlwinm	r1,r0,32-9,30,30	/* _PAGE_RW -> PP msb */
+	rlwinm	r1,r0,32-9,30,30	/* _PAGE_WRITE -> PP msb */
 	rlwimi	r0,r0,32-1,30,30	/* _PAGE_USER -> PP msb */
-	rlwimi	r1,r0,32-3,24,24	/* _PAGE_RW -> _PAGE_DIRTY */
+	rlwimi	r1,r0,32-3,24,24	/* _PAGE_WRITE -> _PAGE_DIRTY */
 	rlwimi	r0,r0,32-1,31,31	/* _PAGE_USER -> PP lsb */
 	xori	r1,r1,_PAGE_DIRTY	/* clear dirty when not rw */
 	ori	r1,r1,0xe04		/* clear out reserved bits */
@@ -689,7 +689,7 @@ hash_page_dsi:
 	mfdar	r4
 	mfsrr0	r5
 	mfsrr1	r9
-	rlwinm	r3, r3, 32 - 15, _PAGE_RW	/* DSISR_STORE -> _PAGE_RW */
+	rlwinm	r3, r3, 32 - 15, _PAGE_WRITE	/* DSISR_STORE -> _PAGE_WRITE */
 	bl	hash_page
 	mfspr	r10, SPRN_SPRG_THREAD
 	restore_regs_thread r10
diff --git a/arch/powerpc/mm/book3s32/hash_low.S b/arch/powerpc/mm/book3s32/hash_low.S
index 8b804e1a9fa4..acb0584c174c 100644
--- a/arch/powerpc/mm/book3s32/hash_low.S
+++ b/arch/powerpc/mm/book3s32/hash_low.S
@@ -37,7 +37,7 @@
 /*
  * Load a PTE into the hash table, if possible.
  * The address is in r4, and r3 contains an access flag:
- * _PAGE_RW (0x400) if a write.
+ * _PAGE_WRITE (0x400) if a write.
  * r9 contains the SRR1 value, from which we use the MSR_PR bit.
  * SPRG_THREAD contains the physical address of the current task's thread.
  *
@@ -113,15 +113,15 @@ _GLOBAL(hash_page)
 	lwarx	r6,0,r8			/* get linux-style pte, flag word */
 #ifdef CONFIG_PPC_KUAP
 	mfsrin	r5,r4
-	rlwinm	r0,r9,28,_PAGE_RW	/* MSR[PR] => _PAGE_RW */
-	rlwinm	r5,r5,12,_PAGE_RW	/* Ks => _PAGE_RW */
+	rlwinm	r0,r9,28,_PAGE_WRITE	/* MSR[PR] => _PAGE_WRITE */
+	rlwinm	r5,r5,12,_PAGE_WRITE	/* Ks => _PAGE_WRITE */
 	andc	r5,r5,r0		/* Ks & ~MSR[PR] */
-	andc	r5,r6,r5		/* Clear _PAGE_RW when Ks = 1 && MSR[PR] = 0 */
+	andc	r5,r6,r5		/* Clear _PAGE_WRITE when Ks = 1 && MSR[PR] = 0 */
 	andc.	r5,r3,r5		/* check access & ~permission */
 #else
 	andc.	r5,r3,r6		/* check access & ~permission */
 #endif
-	rlwinm	r0,r3,32-3,24,24	/* _PAGE_RW access -> _PAGE_DIRTY */
+	rlwinm	r0,r3,32-3,24,24	/* _PAGE_WRITE access -> _PAGE_DIRTY */
 	ori	r0,r0,_PAGE_ACCESSED|_PAGE_HASHPTE
 #ifdef CONFIG_SMP
 	bne-	.Lhash_page_out		/* return if access not permitted */
@@ -307,7 +307,7 @@ Hash_msk = (((1 << Hash_bits) - 1) * 64)
 __REF
 _GLOBAL(create_hpte)
 	/* Convert linux-style PTE (r5) to low word of PPC-style PTE (r8) */
-	rlwinm	r8,r5,32-9,30,30	/* _PAGE_RW -> PP msb */
+	rlwinm	r8,r5,32-9,30,30	/* _PAGE_WRITE -> PP msb */
 	rlwinm	r0,r5,32-6,30,30	/* _PAGE_DIRTY -> PP msb */
 	and	r8,r8,r0		/* writable if _RW & _DIRTY */
 	rlwimi	r5,r5,32-1,30,30	/* _PAGE_USER -> PP msb */
diff --git a/arch/powerpc/mm/book3s32/mmu.c b/arch/powerpc/mm/book3s32/mmu.c
index d1041c946ce2..06bf0972792d 100644
--- a/arch/powerpc/mm/book3s32/mmu.c
+++ b/arch/powerpc/mm/book3s32/mmu.c
@@ -277,7 +277,7 @@ void __init setbat(int index, unsigned long virt, phys_addr_t phys,
 	/* Do DBAT first */
 	wimgxpp = flags & (_PAGE_WRITETHRU | _PAGE_NO_CACHE
 			   | _PAGE_COHERENT | _PAGE_GUARDED);
-	wimgxpp |= (flags & _PAGE_RW)? BPP_RW: BPP_RX;
+	wimgxpp |= (flags & _PAGE_WRITE)? BPP_RW: BPP_RX;
 	bat[1].batu = virt | (bl << 2) | 2; /* Vs=1, Vp=0 */
 	bat[1].batl = BAT_PHYS_ADDR(phys) | wimgxpp;
 	if (!is_kernel_addr(virt))
-- 
2.41.0


^ permalink raw reply related	[flat|nested] 50+ messages in thread

* [PATCH v2 34/37] powerpc/32s: Introduce _PAGE_READ and remove _PAGE_USER
  2023-09-25 18:31 [PATCH v2 00/37] Implement execute-only protection on powerpc Christophe Leroy
                   ` (32 preceding siblings ...)
  2023-09-25 18:31 ` [PATCH v2 33/37] powerpc/32s: Add _PAGE_WRITE to supplement _PAGE_RW Christophe Leroy
@ 2023-09-25 18:31 ` Christophe Leroy
  2023-09-25 18:31 ` [PATCH v2 35/37] powerpc/ptdump: Display _PAGE_READ and _PAGE_WRITE Christophe Leroy
                   ` (4 subsequent siblings)
  38 siblings, 0 replies; 50+ messages in thread
From: Christophe Leroy @ 2023-09-25 18:31 UTC (permalink / raw)
  To: Michael Ellerman, Nicholas Piggin; +Cc: linuxppc-dev, linux-kernel

On 603 MMU, TLB missed are handled by SW and there are separated
DTLB and ITLB. It is therefore possible to implement execute-only
protection by not loading DTLB when read access is not permitted.

To do that, _PAGE_READ flag is needed but there is no bit available
for it in PTE. On the other hand the only real use of _PAGE_USER is
to implement PAGE_NONE by clearing _PAGE_USER.

As _PAGE_NONE can also be implemented by clearing _PAGE_READ, remove
_PAGE_USER and add _PAGE_READ. Then use the virtual address to know
whether user rights or kernel rights are to be used.

With that change, 603 MMU now honors execute-only protection.

For hash (604) MMU it is more tricky because hash table is common to
load/store and execute. Nevertheless it is still possible to check
whether _PAGE_READ is set before loading hash table for a load/store
access. At least it can't be read unless it is executed first.

Signed-off-by: Christophe Leroy <christophe.leroy@csgroup.eu>
---
 arch/powerpc/include/asm/book3s/32/pgtable.h | 48 ++++-----------
 arch/powerpc/kernel/head_book3s_32.S         | 61 +++++++++++---------
 arch/powerpc/mm/book3s32/hash_low.S          | 22 ++++---
 3 files changed, 60 insertions(+), 71 deletions(-)

diff --git a/arch/powerpc/include/asm/book3s/32/pgtable.h b/arch/powerpc/include/asm/book3s/32/pgtable.h
index 480ad6b4fd6f..244621c88510 100644
--- a/arch/powerpc/include/asm/book3s/32/pgtable.h
+++ b/arch/powerpc/include/asm/book3s/32/pgtable.h
@@ -20,7 +20,7 @@
 
 #define _PAGE_PRESENT	0x001	/* software: pte contains a translation */
 #define _PAGE_HASHPTE	0x002	/* hash_page has made an HPTE for this pte */
-#define _PAGE_USER	0x004	/* usermode access allowed */
+#define _PAGE_READ	0x004	/* software: read access allowed */
 #define _PAGE_GUARDED	0x008	/* G: prohibit speculative access */
 #define _PAGE_COHERENT	0x010	/* M: enforce memory coherence (SMP systems) */
 #define _PAGE_NO_CACHE	0x020	/* I: cache inhibit */
@@ -28,11 +28,9 @@
 #define _PAGE_DIRTY	0x080	/* C: page changed */
 #define _PAGE_ACCESSED	0x100	/* R: page referenced */
 #define _PAGE_EXEC	0x200	/* software: exec allowed */
-#define _PAGE_RW	0x400	/* software: user write access allowed */
+#define _PAGE_WRITE	0x400	/* software: user write access allowed */
 #define _PAGE_SPECIAL	0x800	/* software: Special page */
 
-#define _PAGE_WRITE	_PAGE_RW
-
 #ifdef CONFIG_PTE_64BIT
 /* We never clear the high word of the pte */
 #define _PTE_NONE_MASK	(0xffffffff00000000ULL | _PAGE_HASHPTE)
@@ -44,26 +42,13 @@
 #define _PMD_PRESENT_MASK (PAGE_MASK)
 #define _PMD_BAD	(~PAGE_MASK)
 
-/* We borrow the _PAGE_USER bit to store the exclusive marker in swap PTEs. */
-#define _PAGE_SWP_EXCLUSIVE	_PAGE_USER
+/* We borrow the _PAGE_READ bit to store the exclusive marker in swap PTEs. */
+#define _PAGE_SWP_EXCLUSIVE	_PAGE_READ
 
 /* And here we include common definitions */
 
-#define _PAGE_KERNEL_RO		0
-#define _PAGE_KERNEL_ROX	(_PAGE_EXEC)
-#define _PAGE_KERNEL_RW		(_PAGE_DIRTY | _PAGE_RW)
-#define _PAGE_KERNEL_RWX	(_PAGE_DIRTY | _PAGE_RW | _PAGE_EXEC)
-
 #define _PAGE_HPTEFLAGS _PAGE_HASHPTE
 
-#ifndef __ASSEMBLY__
-
-static inline bool pte_user(pte_t pte)
-{
-	return pte_val(pte) & _PAGE_USER;
-}
-#endif /* __ASSEMBLY__ */
-
 /*
  * Location of the PFN in the PTE. Most 32-bit platforms use the same
  * as _PAGE_SHIFT here (ie, naturally aligned).
@@ -99,20 +84,7 @@ static inline bool pte_user(pte_t pte)
 #define _PAGE_BASE_NC	(_PAGE_PRESENT | _PAGE_ACCESSED)
 #define _PAGE_BASE	(_PAGE_BASE_NC | _PAGE_COHERENT)
 
-/*
- * Permission masks used to generate the __P and __S table.
- *
- * Note:__pgprot is defined in arch/powerpc/include/asm/page.h
- *
- * Write permissions imply read permissions for now.
- */
-#define PAGE_NONE	__pgprot(_PAGE_BASE)
-#define PAGE_SHARED	__pgprot(_PAGE_BASE | _PAGE_USER | _PAGE_RW)
-#define PAGE_SHARED_X	__pgprot(_PAGE_BASE | _PAGE_USER | _PAGE_RW | _PAGE_EXEC)
-#define PAGE_COPY	__pgprot(_PAGE_BASE | _PAGE_USER)
-#define PAGE_COPY_X	__pgprot(_PAGE_BASE | _PAGE_USER | _PAGE_EXEC)
-#define PAGE_READONLY	__pgprot(_PAGE_BASE | _PAGE_USER)
-#define PAGE_READONLY_X	__pgprot(_PAGE_BASE | _PAGE_USER | _PAGE_EXEC)
+#include <asm/pgtable-masks.h>
 
 /* Permission masks used for kernel mappings */
 #define PAGE_KERNEL	__pgprot(_PAGE_BASE | _PAGE_KERNEL_RW)
@@ -408,12 +380,16 @@ static inline pte_t pte_swp_clear_exclusive(pte_t pte)
 }
 
 /* Generic accessors to PTE bits */
+static inline bool pte_read(pte_t pte)
+{
+	return !!(pte_val(pte) & _PAGE_READ);
+}
+
 static inline bool pte_write(pte_t pte)
 {
 	return !!(pte_val(pte) & _PAGE_WRITE);
 }
 
-static inline int pte_read(pte_t pte)		{ return 1; }
 static inline int pte_dirty(pte_t pte)		{ return !!(pte_val(pte) & _PAGE_DIRTY); }
 static inline int pte_young(pte_t pte)		{ return !!(pte_val(pte) & _PAGE_ACCESSED); }
 static inline int pte_special(pte_t pte)	{ return !!(pte_val(pte) & _PAGE_SPECIAL); }
@@ -448,10 +424,10 @@ static inline bool pte_ci(pte_t pte)
 static inline bool pte_access_permitted(pte_t pte, bool write)
 {
 	/*
-	 * A read-only access is controlled by _PAGE_USER bit.
+	 * A read-only access is controlled by _PAGE_READ bit.
 	 * We have _PAGE_READ set for WRITE and EXECUTE
 	 */
-	if (!pte_present(pte) || !pte_user(pte) || !pte_read(pte))
+	if (!pte_present(pte) || !pte_read(pte))
 		return false;
 
 	if (write && !pte_write(pte))
diff --git a/arch/powerpc/kernel/head_book3s_32.S b/arch/powerpc/kernel/head_book3s_32.S
index 615d429d7bd1..c1d89764dd22 100644
--- a/arch/powerpc/kernel/head_book3s_32.S
+++ b/arch/powerpc/kernel/head_book3s_32.S
@@ -412,10 +412,10 @@ END_FTR_SECTION_IFSET(CPU_FTR_FPU_UNAVAILABLE)
 	. = INTERRUPT_INST_TLB_MISS_603
 InstructionTLBMiss:
 /*
- * r0:	scratch
+ * r0:	userspace flag (later scratch)
  * r1:	linux style pte ( later becomes ppc hardware pte )
  * r2:	ptr to linux-style pte
- * r3:	scratch
+ * r3:	fault address
  */
 	/* Get PTE (linux-style) and check access */
 	mfspr	r3,SPRN_IMISS
@@ -424,12 +424,13 @@ InstructionTLBMiss:
 	cmplw	0,r1,r3
 #endif
 	mfspr	r2, SPRN_SDR1
-	li	r1,_PAGE_PRESENT | _PAGE_ACCESSED | _PAGE_EXEC | _PAGE_USER
+	li	r1,_PAGE_PRESENT | _PAGE_ACCESSED | _PAGE_EXEC
 	rlwinm	r2, r2, 28, 0xfffff000
 #ifdef CONFIG_MODULES
+	li	r0, 3
 	bgt-	112f
 	lis	r2, (swapper_pg_dir - PAGE_OFFSET)@ha	/* if kernel address, use */
-	li	r1,_PAGE_PRESENT | _PAGE_ACCESSED | _PAGE_EXEC
+	li	r0, 0
 	addi	r2, r2, (swapper_pg_dir - PAGE_OFFSET)@l	/* kernel page table */
 #endif
 112:	rlwimi	r2,r3,12,20,29		/* insert top 10 bits of address */
@@ -437,13 +438,15 @@ InstructionTLBMiss:
 	rlwinm.	r2,r2,0,0,19		/* extract address of pte page */
 	beq-	InstructionAddressInvalid	/* return if no mapping */
 	rlwimi	r2,r3,22,20,29		/* insert next 10 bits of address */
-	lwz	r0,0(r2)		/* get linux-style pte */
-	andc.	r1,r1,r0		/* check access & ~permission */
+	lwz	r2,0(r2)		/* get linux-style pte */
+	andc.	r1,r1,r2		/* check access & ~permission */
 	bne-	InstructionAddressInvalid /* return if access not permitted */
 	/* Convert linux-style PTE to low word of PPC-style PTE */
-	rlwimi	r0,r0,32-2,31,31	/* _PAGE_USER -> PP lsb */
+#ifdef CONFIG_MODULES
+	rlwimi	r2, r0, 0, 31, 31	/* userspace ? -> PP lsb */
+#endif
 	ori	r1, r1, 0xe06		/* clear out reserved bits */
-	andc	r1, r0, r1		/* PP = user? 1 : 0 */
+	andc	r1, r2, r1		/* PP = user? 1 : 0 */
 BEGIN_FTR_SECTION
 	rlwinm	r1,r1,0,~_PAGE_COHERENT	/* clear M (coherence not required) */
 END_FTR_SECTION_IFCLR(CPU_FTR_NEED_COHERENT)
@@ -478,38 +481,38 @@ InstructionAddressInvalid:
 	. = INTERRUPT_DATA_LOAD_TLB_MISS_603
 DataLoadTLBMiss:
 /*
- * r0:	scratch
+ * r0:	userspace flag (later scratch)
  * r1:	linux style pte ( later becomes ppc hardware pte )
  * r2:	ptr to linux-style pte
- * r3:	scratch
+ * r3:	fault address
  */
 	/* Get PTE (linux-style) and check access */
 	mfspr	r3,SPRN_DMISS
 	lis	r1, TASK_SIZE@h		/* check if kernel address */
 	cmplw	0,r1,r3
 	mfspr	r2, SPRN_SDR1
-	li	r1, _PAGE_PRESENT | _PAGE_ACCESSED | _PAGE_USER
+	li	r1, _PAGE_PRESENT | _PAGE_ACCESSED | _PAGE_READ
 	rlwinm	r2, r2, 28, 0xfffff000
+	li	r0, 3
 	bgt-	112f
 	lis	r2, (swapper_pg_dir - PAGE_OFFSET)@ha	/* if kernel address, use */
-	li	r1, _PAGE_PRESENT | _PAGE_ACCESSED
+	li	r0, 0
 	addi	r2, r2, (swapper_pg_dir - PAGE_OFFSET)@l	/* kernel page table */
 112:	rlwimi	r2,r3,12,20,29		/* insert top 10 bits of address */
 	lwz	r2,0(r2)		/* get pmd entry */
 	rlwinm.	r2,r2,0,0,19		/* extract address of pte page */
 	beq-	DataAddressInvalid	/* return if no mapping */
 	rlwimi	r2,r3,22,20,29		/* insert next 10 bits of address */
-	lwz	r0,0(r2)		/* get linux-style pte */
-	andc.	r1,r1,r0		/* check access & ~permission */
+	lwz	r2,0(r2)		/* get linux-style pte */
+	andc.	r1,r1,r2		/* check access & ~permission */
 	bne-	DataAddressInvalid	/* return if access not permitted */
 	/* Convert linux-style PTE to low word of PPC-style PTE */
-	rlwinm	r1,r0,32-9,30,30	/* _PAGE_WRITE -> PP msb */
-	rlwimi	r0,r0,32-1,30,30	/* _PAGE_USER -> PP msb */
-	rlwimi	r1,r0,32-3,24,24	/* _PAGE_WRITE -> _PAGE_DIRTY */
-	rlwimi	r0,r0,32-1,31,31	/* _PAGE_USER -> PP lsb */
+	rlwinm	r1,r2,32-9,30,30	/* _PAGE_WRITE -> PP msb */
+	rlwimi	r2,r0,0,30,31		/* userspace ? -> PP */
+	rlwimi	r1,r2,32-3,24,24	/* _PAGE_WRITE -> _PAGE_DIRTY */
 	xori	r1,r1,_PAGE_DIRTY	/* clear dirty when not rw */
 	ori	r1,r1,0xe04		/* clear out reserved bits */
-	andc	r1,r0,r1		/* PP = user? rw? 1: 3: 0 */
+	andc	r1,r2,r1		/* PP = user? rw? 1: 3: 0 */
 BEGIN_FTR_SECTION
 	rlwinm	r1,r1,0,~_PAGE_COHERENT	/* clear M (coherence not required) */
 END_FTR_SECTION_IFCLR(CPU_FTR_NEED_COHERENT)
@@ -558,34 +561,35 @@ DataAddressInvalid:
 	. = INTERRUPT_DATA_STORE_TLB_MISS_603
 DataStoreTLBMiss:
 /*
- * r0:	scratch
+ * r0:	userspace flag (later scratch)
  * r1:	linux style pte ( later becomes ppc hardware pte )
  * r2:	ptr to linux-style pte
- * r3:	scratch
+ * r3:	fault address
  */
 	/* Get PTE (linux-style) and check access */
 	mfspr	r3,SPRN_DMISS
 	lis	r1, TASK_SIZE@h		/* check if kernel address */
 	cmplw	0,r1,r3
 	mfspr	r2, SPRN_SDR1
-	li	r1, _PAGE_RW | _PAGE_DIRTY | _PAGE_PRESENT | _PAGE_ACCESSED | _PAGE_USER
+	li	r1, _PAGE_RW | _PAGE_DIRTY | _PAGE_PRESENT | _PAGE_ACCESSED
 	rlwinm	r2, r2, 28, 0xfffff000
+	li	r0, 3
 	bgt-	112f
 	lis	r2, (swapper_pg_dir - PAGE_OFFSET)@ha	/* if kernel address, use */
-	li	r1, _PAGE_RW | _PAGE_DIRTY | _PAGE_PRESENT | _PAGE_ACCESSED
+	li	r0, 0
 	addi	r2, r2, (swapper_pg_dir - PAGE_OFFSET)@l	/* kernel page table */
 112:	rlwimi	r2,r3,12,20,29		/* insert top 10 bits of address */
 	lwz	r2,0(r2)		/* get pmd entry */
 	rlwinm.	r2,r2,0,0,19		/* extract address of pte page */
 	beq-	DataAddressInvalid	/* return if no mapping */
 	rlwimi	r2,r3,22,20,29		/* insert next 10 bits of address */
-	lwz	r0,0(r2)		/* get linux-style pte */
-	andc.	r1,r1,r0		/* check access & ~permission */
+	lwz	r2,0(r2)		/* get linux-style pte */
+	andc.	r1,r1,r2		/* check access & ~permission */
 	bne-	DataAddressInvalid	/* return if access not permitted */
 	/* Convert linux-style PTE to low word of PPC-style PTE */
-	rlwimi	r0,r0,32-2,31,31	/* _PAGE_USER -> PP lsb */
+	rlwimi	r2,r0,0,31,31		/* userspace ? -> PP lsb */
 	li	r1,0xe06		/* clear out reserved bits & PP msb */
-	andc	r1,r0,r1		/* PP = user? 1: 0 */
+	andc	r1,r2,r1		/* PP = user? 1: 0 */
 BEGIN_FTR_SECTION
 	rlwinm	r1,r1,0,~_PAGE_COHERENT	/* clear M (coherence not required) */
 END_FTR_SECTION_IFCLR(CPU_FTR_NEED_COHERENT)
@@ -690,6 +694,7 @@ hash_page_dsi:
 	mfsrr0	r5
 	mfsrr1	r9
 	rlwinm	r3, r3, 32 - 15, _PAGE_WRITE	/* DSISR_STORE -> _PAGE_WRITE */
+	ori	r3, r3, _PAGE_PRESENT | _PAGE_READ
 	bl	hash_page
 	mfspr	r10, SPRN_SPRG_THREAD
 	restore_regs_thread r10
@@ -699,7 +704,7 @@ hash_page_isi:
 	mr	r11, r10
 	mfspr	r10, SPRN_SPRG_THREAD
 	save_regs_thread	r10
-	li	r3, 0
+	li	r3, _PAGE_PRESENT | _PAGE_EXEC
 	lwz	r4, SRR0(r10)
 	lwz	r9, SRR1(r10)
 	bl	hash_page
diff --git a/arch/powerpc/mm/book3s32/hash_low.S b/arch/powerpc/mm/book3s32/hash_low.S
index acb0584c174c..4ed0efd03db5 100644
--- a/arch/powerpc/mm/book3s32/hash_low.S
+++ b/arch/powerpc/mm/book3s32/hash_low.S
@@ -36,8 +36,9 @@
 
 /*
  * Load a PTE into the hash table, if possible.
- * The address is in r4, and r3 contains an access flag:
- * _PAGE_WRITE (0x400) if a write.
+ * The address is in r4, and r3 contains required access flags:
+ *   - For ISI: _PAGE_PRESENT | _PAGE_EXEC
+ *   - For DSI: _PAGE_PRESENT | _PAGE_READ | _PAGE_WRITE if a write.
  * r9 contains the SRR1 value, from which we use the MSR_PR bit.
  * SPRG_THREAD contains the physical address of the current task's thread.
  *
@@ -67,12 +68,16 @@ _GLOBAL(hash_page)
 	lis	r0, TASK_SIZE@h		/* check if kernel address */
 	cmplw	0,r4,r0
 	mfspr	r8,SPRN_SPRG_THREAD	/* current task's THREAD (phys) */
-	ori	r3,r3,_PAGE_USER|_PAGE_PRESENT /* test low addresses as user */
 	lwz	r5,PGDIR(r8)		/* virt page-table root */
 	blt+	112f			/* assume user more likely */
 	lis	r5,swapper_pg_dir@ha	/* if kernel address, use */
+	andi.	r0,r9,MSR_PR		/* Check usermode */
 	addi	r5,r5,swapper_pg_dir@l	/* kernel page table */
-	rlwimi	r3,r9,32-12,29,29	/* MSR_PR -> _PAGE_USER */
+#ifdef CONFIG_SMP
+	bne-	.Lhash_page_out		/* return if usermode */
+#else
+	bnelr-
+#endif
 112:	tophys(r5, r5)
 #ifndef CONFIG_PTE_64BIT
 	rlwimi	r5,r4,12,20,29		/* insert top 10 bits of address */
@@ -307,12 +312,15 @@ Hash_msk = (((1 << Hash_bits) - 1) * 64)
 __REF
 _GLOBAL(create_hpte)
 	/* Convert linux-style PTE (r5) to low word of PPC-style PTE (r8) */
+	lis	r0, TASK_SIZE@h
+	rlwinm	r5,r5,0,~3		/* Clear PP bits */
+	cmplw	r4,r0
 	rlwinm	r8,r5,32-9,30,30	/* _PAGE_WRITE -> PP msb */
 	rlwinm	r0,r5,32-6,30,30	/* _PAGE_DIRTY -> PP msb */
 	and	r8,r8,r0		/* writable if _RW & _DIRTY */
-	rlwimi	r5,r5,32-1,30,30	/* _PAGE_USER -> PP msb */
-	rlwimi	r5,r5,32-2,31,31	/* _PAGE_USER -> PP lsb */
-	ori	r8,r8,0xe04		/* clear out reserved bits */
+	bge-	1f			/* Kernelspace ? Skip */
+	ori	r5,r5,3			/* Userspace ? PP = 3 */
+1:	ori	r8,r8,0xe04		/* clear out reserved bits */
 	andc	r8,r5,r8		/* PP = user? (rw&dirty? 1: 3): 0 */
 BEGIN_FTR_SECTION
 	rlwinm	r8,r8,0,~_PAGE_COHERENT	/* clear M (coherence not required) */
-- 
2.41.0


^ permalink raw reply related	[flat|nested] 50+ messages in thread

* [PATCH v2 35/37] powerpc/ptdump: Display _PAGE_READ and _PAGE_WRITE
  2023-09-25 18:31 [PATCH v2 00/37] Implement execute-only protection on powerpc Christophe Leroy
                   ` (33 preceding siblings ...)
  2023-09-25 18:31 ` [PATCH v2 34/37] powerpc/32s: Introduce _PAGE_READ and remove _PAGE_USER Christophe Leroy
@ 2023-09-25 18:31 ` Christophe Leroy
  2023-09-25 18:31 ` [PATCH v2 36/37] powerpc: Finally remove _PAGE_USER Christophe Leroy
                   ` (3 subsequent siblings)
  38 siblings, 0 replies; 50+ messages in thread
From: Christophe Leroy @ 2023-09-25 18:31 UTC (permalink / raw)
  To: Michael Ellerman, Nicholas Piggin; +Cc: linuxppc-dev, linux-kernel

Instead of always displaying either 'rw' or 'r ' depending on
_PAGE_RW, display 'r' or ' ' for _PAGE_READ and 'w' or ' '
for _PAGE_WRITE.

Signed-off-by: Christophe Leroy <christophe.leroy@csgroup.eu>
---
 arch/powerpc/mm/ptdump/shared.c | 11 ++++++++---
 1 file changed, 8 insertions(+), 3 deletions(-)

diff --git a/arch/powerpc/mm/ptdump/shared.c b/arch/powerpc/mm/ptdump/shared.c
index 5ff101654c45..39c30c62b7ea 100644
--- a/arch/powerpc/mm/ptdump/shared.c
+++ b/arch/powerpc/mm/ptdump/shared.c
@@ -11,10 +11,15 @@
 
 static const struct flag_info flag_array[] = {
 	{
-		.mask	= _PAGE_RW,
+		.mask	= _PAGE_READ,
 		.val	= 0,
-		.set	= "r ",
-		.clear	= "rw",
+		.set	= " ",
+		.clear	= "r",
+	}, {
+		.mask	= _PAGE_WRITE,
+		.val	= 0,
+		.set	= " ",
+		.clear	= "w",
 	}, {
 		.mask	= _PAGE_EXEC,
 		.val	= _PAGE_EXEC,
-- 
2.41.0


^ permalink raw reply related	[flat|nested] 50+ messages in thread

* [PATCH v2 36/37] powerpc: Finally remove _PAGE_USER
  2023-09-25 18:31 [PATCH v2 00/37] Implement execute-only protection on powerpc Christophe Leroy
                   ` (34 preceding siblings ...)
  2023-09-25 18:31 ` [PATCH v2 35/37] powerpc/ptdump: Display _PAGE_READ and _PAGE_WRITE Christophe Leroy
@ 2023-09-25 18:31 ` Christophe Leroy
  2023-09-25 18:31 ` [PATCH v2 37/37] powerpc: Support execute-only on all powerpc Christophe Leroy
                   ` (2 subsequent siblings)
  38 siblings, 0 replies; 50+ messages in thread
From: Christophe Leroy @ 2023-09-25 18:31 UTC (permalink / raw)
  To: Michael Ellerman, Nicholas Piggin; +Cc: linuxppc-dev, linux-kernel

_PAGE_USER is now gone on all targets. Remove it completely.

Signed-off-by: Christophe Leroy <christophe.leroy@csgroup.eu>
---
 arch/powerpc/include/asm/nohash/pgtable.h | 10 +++-------
 1 file changed, 3 insertions(+), 7 deletions(-)

diff --git a/arch/powerpc/include/asm/nohash/pgtable.h b/arch/powerpc/include/asm/nohash/pgtable.h
index aba56fe3b1c6..f922c84b23eb 100644
--- a/arch/powerpc/include/asm/nohash/pgtable.h
+++ b/arch/powerpc/include/asm/nohash/pgtable.h
@@ -183,18 +183,14 @@ static inline int pte_young(pte_t pte)
 }
 
 /*
- * Don't just check for any non zero bits in __PAGE_USER, since for book3e
+ * Don't just check for any non zero bits in __PAGE_READ, since for book3e
  * and PTE_64BIT, PAGE_KERNEL_X contains _PAGE_BAP_SR which is also in
- * _PAGE_USER.  Need to explicitly match _PAGE_BAP_UR bit in that case too.
+ * _PAGE_READ.  Need to explicitly match _PAGE_BAP_UR bit in that case too.
  */
 #ifndef pte_read
 static inline bool pte_read(pte_t pte)
 {
-#ifdef _PAGE_READ
 	return (pte_val(pte) & _PAGE_READ) == _PAGE_READ;
-#else
-	return (pte_val(pte) & _PAGE_USER) == _PAGE_USER;
-#endif
 }
 #endif
 
@@ -206,7 +202,7 @@ static inline bool pte_read(pte_t pte)
 static inline bool pte_access_permitted(pte_t pte, bool write)
 {
 	/*
-	 * A read-only access is controlled by _PAGE_USER bit.
+	 * A read-only access is controlled by _PAGE_READ bit.
 	 * We have _PAGE_READ set for WRITE and EXECUTE
 	 */
 	if (!pte_present(pte) || !pte_read(pte))
-- 
2.41.0


^ permalink raw reply related	[flat|nested] 50+ messages in thread

* [PATCH v2 37/37] powerpc: Support execute-only on all powerpc
  2023-09-25 18:31 [PATCH v2 00/37] Implement execute-only protection on powerpc Christophe Leroy
                   ` (35 preceding siblings ...)
  2023-09-25 18:31 ` [PATCH v2 36/37] powerpc: Finally remove _PAGE_USER Christophe Leroy
@ 2023-09-25 18:31 ` Christophe Leroy
  2023-11-02  5:39   ` Aneesh Kumar K.V
  2023-10-15 10:00 ` (subset) [PATCH v2 00/37] Implement execute-only protection on powerpc Michael Ellerman
  2023-10-27  9:59 ` Michael Ellerman
  38 siblings, 1 reply; 50+ messages in thread
From: Christophe Leroy @ 2023-09-25 18:31 UTC (permalink / raw)
  To: Michael Ellerman, Nicholas Piggin
  Cc: Kees Cook, linuxppc-dev, linux-kernel, Russell Currey

Introduce PAGE_EXECONLY_X macro which provides exec-only rights.
The _X may be seen as redundant with the EXECONLY but it helps
keep consistancy, all macros having the EXEC right have _X.

And put it next to PAGE_NONE as PAGE_EXECONLY_X is
somehow PAGE_NONE + EXEC just like all other SOMETHING_X are
just SOMETHING + EXEC.

On book3s/64 PAGE_EXECONLY becomes PAGE_READONLY_X.

On book3s/64, as PAGE_EXECONLY is only valid for Radix add
VM_READ flag in vm_get_page_prot() for non-Radix.

And update access_error() so that a non exec fault on a VM_EXEC only
mapping is always invalid, even when the underlying layer don't
always generate a fault for that.

For 8xx, set PAGE_EXECONLY_X as _PAGE_NA | _PAGE_EXEC.
For others, only set it as just _PAGE_EXEC

With that change, 8xx, e500 and 44x fully honor execute-only
protection.

On 40x that is a partial implementation of execute-only. The
implementation won't be complete because once a TLB has been loaded
via the Instruction TLB miss handler, it will be possible to read
the page. But at least it can't be read unless it is executed first.

On 603 MMU, TLB missed are handled by SW and there are separate
DTLB and ITLB. Execute-only is therefore now supported by not loading
DTLB when read access is not permitted.

On hash (604) MMU it is more tricky because hash table is common to
load/store and execute. Nevertheless it is still possible to check
whether _PAGE_READ is set before loading hash table for a load/store
access. At least it can't be read unless it is executed first.

Signed-off-by: Christophe Leroy <christophe.leroy@csgroup.eu>
Cc: Russell Currey <ruscur@russell.cc>
Cc: Kees Cook <keescook@chromium.org>
---
 arch/powerpc/include/asm/book3s/32/pgtable.h |  2 +-
 arch/powerpc/include/asm/book3s/64/pgtable.h |  4 +---
 arch/powerpc/include/asm/nohash/32/pte-8xx.h |  1 +
 arch/powerpc/include/asm/nohash/pgtable.h    |  2 +-
 arch/powerpc/include/asm/nohash/pte-e500.h   |  1 +
 arch/powerpc/include/asm/pgtable-masks.h     |  2 ++
 arch/powerpc/mm/book3s64/pgtable.c           | 10 ++++------
 arch/powerpc/mm/fault.c                      |  9 +++++----
 arch/powerpc/mm/pgtable.c                    |  4 ++--
 9 files changed, 18 insertions(+), 17 deletions(-)

diff --git a/arch/powerpc/include/asm/book3s/32/pgtable.h b/arch/powerpc/include/asm/book3s/32/pgtable.h
index 244621c88510..52971ee30717 100644
--- a/arch/powerpc/include/asm/book3s/32/pgtable.h
+++ b/arch/powerpc/include/asm/book3s/32/pgtable.h
@@ -425,7 +425,7 @@ static inline bool pte_access_permitted(pte_t pte, bool write)
 {
 	/*
 	 * A read-only access is controlled by _PAGE_READ bit.
-	 * We have _PAGE_READ set for WRITE and EXECUTE
+	 * We have _PAGE_READ set for WRITE
 	 */
 	if (!pte_present(pte) || !pte_read(pte))
 		return false;
diff --git a/arch/powerpc/include/asm/book3s/64/pgtable.h b/arch/powerpc/include/asm/book3s/64/pgtable.h
index 0fd12bdc7b5e..751b01227e36 100644
--- a/arch/powerpc/include/asm/book3s/64/pgtable.h
+++ b/arch/powerpc/include/asm/book3s/64/pgtable.h
@@ -18,6 +18,7 @@
 #define _PAGE_WRITE		0x00002 /* write access allowed */
 #define _PAGE_READ		0x00004	/* read access allowed */
 #define _PAGE_NA		_PAGE_PRIVILEGED
+#define _PAGE_NAX		_PAGE_EXEC
 #define _PAGE_RO		_PAGE_READ
 #define _PAGE_ROX		(_PAGE_READ | _PAGE_EXEC)
 #define _PAGE_RW		(_PAGE_READ | _PAGE_WRITE)
@@ -141,9 +142,6 @@
 
 #include <asm/pgtable-masks.h>
 
-/* Radix only, Hash uses PAGE_READONLY_X + execute-only pkey instead */
-#define PAGE_EXECONLY	__pgprot(_PAGE_BASE | _PAGE_EXEC)
-
 /* Permission masks used for kernel mappings */
 #define PAGE_KERNEL	__pgprot(_PAGE_BASE | _PAGE_KERNEL_RW)
 #define PAGE_KERNEL_NC	__pgprot(_PAGE_BASE_NC | _PAGE_KERNEL_RW | _PAGE_TOLERANT)
diff --git a/arch/powerpc/include/asm/nohash/32/pte-8xx.h b/arch/powerpc/include/asm/nohash/32/pte-8xx.h
index 1ee38befd29a..137dc3c84e45 100644
--- a/arch/powerpc/include/asm/nohash/32/pte-8xx.h
+++ b/arch/powerpc/include/asm/nohash/32/pte-8xx.h
@@ -48,6 +48,7 @@
 
 #define _PAGE_HUGE	0x0800	/* Copied to L1 PS bit 29 */
 
+#define _PAGE_NAX	(_PAGE_NA | _PAGE_EXEC)
 #define _PAGE_ROX	(_PAGE_RO | _PAGE_EXEC)
 #define _PAGE_RW	0
 #define _PAGE_RWX	_PAGE_EXEC
diff --git a/arch/powerpc/include/asm/nohash/pgtable.h b/arch/powerpc/include/asm/nohash/pgtable.h
index f922c84b23eb..a50be1de9f83 100644
--- a/arch/powerpc/include/asm/nohash/pgtable.h
+++ b/arch/powerpc/include/asm/nohash/pgtable.h
@@ -203,7 +203,7 @@ static inline bool pte_access_permitted(pte_t pte, bool write)
 {
 	/*
 	 * A read-only access is controlled by _PAGE_READ bit.
-	 * We have _PAGE_READ set for WRITE and EXECUTE
+	 * We have _PAGE_READ set for WRITE
 	 */
 	if (!pte_present(pte) || !pte_read(pte))
 		return false;
diff --git a/arch/powerpc/include/asm/nohash/pte-e500.h b/arch/powerpc/include/asm/nohash/pte-e500.h
index 31d2c3ea7df8..f516f0b5b7a8 100644
--- a/arch/powerpc/include/asm/nohash/pte-e500.h
+++ b/arch/powerpc/include/asm/nohash/pte-e500.h
@@ -57,6 +57,7 @@
 #define _PAGE_KERNEL_ROX	(_PAGE_BAP_SR | _PAGE_BAP_SX)
 
 #define _PAGE_NA	0
+#define _PAGE_NAX	_PAGE_BAP_UX
 #define _PAGE_RO	_PAGE_READ
 #define _PAGE_ROX	(_PAGE_READ | _PAGE_BAP_UX)
 #define _PAGE_RW	(_PAGE_READ | _PAGE_WRITE)
diff --git a/arch/powerpc/include/asm/pgtable-masks.h b/arch/powerpc/include/asm/pgtable-masks.h
index 808a3b9e8fc0..6e8e2db26a5a 100644
--- a/arch/powerpc/include/asm/pgtable-masks.h
+++ b/arch/powerpc/include/asm/pgtable-masks.h
@@ -4,6 +4,7 @@
 
 #ifndef _PAGE_NA
 #define _PAGE_NA	0
+#define _PAGE_NAX	_PAGE_EXEC
 #define _PAGE_RO	_PAGE_READ
 #define _PAGE_ROX	(_PAGE_READ | _PAGE_EXEC)
 #define _PAGE_RW	(_PAGE_READ | _PAGE_WRITE)
@@ -20,6 +21,7 @@
 
 /* Permission masks used to generate the __P and __S table */
 #define PAGE_NONE	__pgprot(_PAGE_BASE | _PAGE_NA)
+#define PAGE_EXECONLY_X	__pgprot(_PAGE_BASE | _PAGE_NAX)
 #define PAGE_SHARED	__pgprot(_PAGE_BASE | _PAGE_RW)
 #define PAGE_SHARED_X	__pgprot(_PAGE_BASE | _PAGE_RWX)
 #define PAGE_COPY	__pgprot(_PAGE_BASE | _PAGE_RO)
diff --git a/arch/powerpc/mm/book3s64/pgtable.c b/arch/powerpc/mm/book3s64/pgtable.c
index 8f8a62d3ff4d..be229290a6a7 100644
--- a/arch/powerpc/mm/book3s64/pgtable.c
+++ b/arch/powerpc/mm/book3s64/pgtable.c
@@ -635,12 +635,10 @@ pgprot_t vm_get_page_prot(unsigned long vm_flags)
 	unsigned long prot;
 
 	/* Radix supports execute-only, but protection_map maps X -> RX */
-	if (radix_enabled() && ((vm_flags & VM_ACCESS_FLAGS) == VM_EXEC)) {
-		prot = pgprot_val(PAGE_EXECONLY);
-	} else {
-		prot = pgprot_val(protection_map[vm_flags &
-						 (VM_ACCESS_FLAGS | VM_SHARED)]);
-	}
+	if (!radix_enabled() && ((vm_flags & VM_ACCESS_FLAGS) == VM_EXEC))
+		vm_flags |= VM_READ;
+
+	prot = pgprot_val(protection_map[vm_flags & (VM_ACCESS_FLAGS | VM_SHARED)]);
 
 	if (vm_flags & VM_SAO)
 		prot |= _PAGE_SAO;
diff --git a/arch/powerpc/mm/fault.c b/arch/powerpc/mm/fault.c
index b1723094d464..9e49ede2bc1c 100644
--- a/arch/powerpc/mm/fault.c
+++ b/arch/powerpc/mm/fault.c
@@ -266,14 +266,15 @@ static bool access_error(bool is_write, bool is_exec, struct vm_area_struct *vma
 	}
 
 	/*
-	 * VM_READ, VM_WRITE and VM_EXEC all imply read permissions, as
-	 * defined in protection_map[].  Read faults can only be caused by
-	 * a PROT_NONE mapping, or with a PROT_EXEC-only mapping on Radix.
+	 * VM_READ, VM_WRITE and VM_EXEC may imply read permissions, as
+	 * defined in protection_map[].  In that case Read faults can only be
+	 * caused by a PROT_NONE mapping. However a non exec access on a
+	 * VM_EXEC only mapping is invalid anyway, so report it as such.
 	 */
 	if (unlikely(!vma_is_accessible(vma)))
 		return true;
 
-	if (unlikely(radix_enabled() && ((vma->vm_flags & VM_ACCESS_FLAGS) == VM_EXEC)))
+	if ((vma->vm_flags & VM_ACCESS_FLAGS) == VM_EXEC)
 		return true;
 
 	/*
diff --git a/arch/powerpc/mm/pgtable.c b/arch/powerpc/mm/pgtable.c
index 781a68c69c2f..79508c1d15d7 100644
--- a/arch/powerpc/mm/pgtable.c
+++ b/arch/powerpc/mm/pgtable.c
@@ -492,7 +492,7 @@ const pgprot_t protection_map[16] = {
 	[VM_READ]					= PAGE_READONLY,
 	[VM_WRITE]					= PAGE_COPY,
 	[VM_WRITE | VM_READ]				= PAGE_COPY,
-	[VM_EXEC]					= PAGE_READONLY_X,
+	[VM_EXEC]					= PAGE_EXECONLY_X,
 	[VM_EXEC | VM_READ]				= PAGE_READONLY_X,
 	[VM_EXEC | VM_WRITE]				= PAGE_COPY_X,
 	[VM_EXEC | VM_WRITE | VM_READ]			= PAGE_COPY_X,
@@ -500,7 +500,7 @@ const pgprot_t protection_map[16] = {
 	[VM_SHARED | VM_READ]				= PAGE_READONLY,
 	[VM_SHARED | VM_WRITE]				= PAGE_SHARED,
 	[VM_SHARED | VM_WRITE | VM_READ]		= PAGE_SHARED,
-	[VM_SHARED | VM_EXEC]				= PAGE_READONLY_X,
+	[VM_SHARED | VM_EXEC]				= PAGE_EXECONLY_X,
 	[VM_SHARED | VM_EXEC | VM_READ]			= PAGE_READONLY_X,
 	[VM_SHARED | VM_EXEC | VM_WRITE]		= PAGE_SHARED_X,
 	[VM_SHARED | VM_EXEC | VM_WRITE | VM_READ]	= PAGE_SHARED_X
-- 
2.41.0


^ permalink raw reply related	[flat|nested] 50+ messages in thread

* Re: (subset) [PATCH v2 00/37] Implement execute-only protection on powerpc
  2023-09-25 18:31 [PATCH v2 00/37] Implement execute-only protection on powerpc Christophe Leroy
                   ` (36 preceding siblings ...)
  2023-09-25 18:31 ` [PATCH v2 37/37] powerpc: Support execute-only on all powerpc Christophe Leroy
@ 2023-10-15 10:00 ` Michael Ellerman
  2023-10-27  9:59 ` Michael Ellerman
  38 siblings, 0 replies; 50+ messages in thread
From: Michael Ellerman @ 2023-10-15 10:00 UTC (permalink / raw)
  To: Nicholas Piggin, Christophe Leroy; +Cc: linuxppc-dev, linux-kernel

On Mon, 25 Sep 2023 20:31:14 +0200, Christophe Leroy wrote:
> This series reworks _PAGE_FLAGS on all platforms in order
> to implement execute-only protection on all powerpc.
> 
> For all targets except 40x and 604 it will be a real execute-only
> protection as the hardware and/or software allows a distinct protection.
> 
> For 40x and 604 that's a poor's man execute-only protection in the
> way that once the page is in the TLB it can be executed. But it's
> better than nothing and allows to have a similar implementation for
> all sorts of powerpc.
> 
> [...]

Patches 1 and 2 applied to powerpc/fixes.

[01/37] powerpc/8xx: Fix pte_access_permitted() for PAGE_NONE
        https://git.kernel.org/powerpc/c/5d9cea8a552ee122e21fbd5a3c5d4eb85f648e06
[02/37] powerpc/64e: Fix wrong test in __ptep_test_and_clear_young()
        https://git.kernel.org/powerpc/c/5ea0bbaa32e8f54e9a57cfee4a3b8769b80be0d2

cheers

^ permalink raw reply	[flat|nested] 50+ messages in thread

* Re: (subset) [PATCH v2 00/37] Implement execute-only protection on powerpc
  2023-09-25 18:31 [PATCH v2 00/37] Implement execute-only protection on powerpc Christophe Leroy
                   ` (37 preceding siblings ...)
  2023-10-15 10:00 ` (subset) [PATCH v2 00/37] Implement execute-only protection on powerpc Michael Ellerman
@ 2023-10-27  9:59 ` Michael Ellerman
  38 siblings, 0 replies; 50+ messages in thread
From: Michael Ellerman @ 2023-10-27  9:59 UTC (permalink / raw)
  To: Nicholas Piggin, Christophe Leroy; +Cc: linuxppc-dev, linux-kernel

On Mon, 25 Sep 2023 20:31:14 +0200, Christophe Leroy wrote:
> This series reworks _PAGE_FLAGS on all platforms in order
> to implement execute-only protection on all powerpc.
> 
> For all targets except 40x and 604 it will be a real execute-only
> protection as the hardware and/or software allows a distinct protection.
> 
> For 40x and 604 that's a poor's man execute-only protection in the
> way that once the page is in the TLB it can be executed. But it's
> better than nothing and allows to have a similar implementation for
> all sorts of powerpc.
> 
> [...]

Applied to powerpc/next.

[03/37] powerpc/40x: Remove stale PTE_ATOMIC_UPDATES macro
        https://git.kernel.org/powerpc/c/cc8ee288f484a2a59c01ccd4d8a417d6ed3466e3
[04/37] powerpc: Remove pte_ERROR()
        https://git.kernel.org/powerpc/c/3b8547ec4d35778c9f4cc261d85c0cae6c1a8ecb
[05/37] powerpc: Deduplicate prototypes of ptep_set_access_flags() and phys_mem_access_prot()
        https://git.kernel.org/powerpc/c/93f81f6eea10f497e892c52998a2194b4e16c91d
[06/37] powerpc: Refactor update_mmu_cache_range()
        https://git.kernel.org/powerpc/c/da9554e0fe3c7b46912a361a803b50f2655ff30f
[07/37] powerpc: Untangle fixmap.h and pgtable.h and mmu.h
        https://git.kernel.org/powerpc/c/d3e01796728add53ab778298573772d44d52d19c
[08/37] powerpc/nohash: Remove {pte/pmd}_protnone()
        https://git.kernel.org/powerpc/c/81fbb9997057b6e6e5795a08d9a8e10e9f48236f
[09/37] powerpc/nohash: Refactor declaration of {map/unmap}_kernel_page()
        https://git.kernel.org/powerpc/c/7835006979e5415aa4c9bc0e3e7063b5c5943ed4
[10/37] powerpc/nohash: Move 8xx version of pte_update() into pte-8xx.h
        https://git.kernel.org/powerpc/c/4c1a89d983be951a3e39d7f9c1d6987f3054e32d
[11/37] powerpc/nohash: Replace #ifdef CONFIG_44x by IS_ENABLED(CONFIG_44x) in pgtable.h
        https://git.kernel.org/powerpc/c/0f4027eab59261f2fb72586f18efb44be3594dd4
[12/37] powerpc/nohash: Refactor pte_update()
        https://git.kernel.org/powerpc/c/42a2722319f0d3d5612ca8efd3ce7d7eae512291
[13/37] powerpc/nohash: Refactor checking of no-change in pte_update()
        https://git.kernel.org/powerpc/c/7c929ad0b3167e980a3963e03403a761138a4350
[14/37] powerpc/nohash: Deduplicate _PAGE_CHG_MASK
        https://git.kernel.org/powerpc/c/27672be7751f25566e69bc228c8b8440a0772f8b
[15/37] powerpc/nohash: Deduplicate pte helpers
        https://git.kernel.org/powerpc/c/3a4288164d631b88a57119777b15099eb23c6fbf
[16/37] powerpc/nohash: Refactor ptep_test_and_clear_young()
        https://git.kernel.org/powerpc/c/8c3d9eb323bbf2b37cdc5c01ebf9604175b5970f
[17/37] powerpc/nohash: Deduplicate ptep_set_wrprotect() and ptep_get_and_clear()
        https://git.kernel.org/powerpc/c/cc68d77febe055b6499dda5fa13bda976a12a85c
[18/37] powerpc/nohash: Refactor pte_clear()
        https://git.kernel.org/powerpc/c/2ef9f4bb9c47ed30ff3c7961744cae545c034154
[19/37] powerpc/nohash: Refactor __ptep_set_access_flags()
        https://git.kernel.org/powerpc/c/799d8836a7c4f4327833e4a5ca952a1700acdb14
[20/37] powerpc/e500: Simplify pte_mkexec()
        https://git.kernel.org/powerpc/c/4c8dd6c9872d4e89fd2b3a6fc92fd6cc9cdce347
[21/37] powerpc: Implement and use pgprot_nx()
        https://git.kernel.org/powerpc/c/d3c0dfcfc95796701e82719722fd997ec5256013
[22/37] powerpc: Fail ioremap() instead of silently ignoring flags when PAGE_USER is set
        https://git.kernel.org/powerpc/c/c7263f156395d1f2a2142375a75b7b040686a07a
[23/37] powerpc: Remove pte_mkuser() and pte_mkpriviledged()
        https://git.kernel.org/powerpc/c/69339071bb27f0b1371cd23d6dada3f976261c20
[24/37] powerpc: Rely on address instead of pte_user()
        https://git.kernel.org/powerpc/c/a78587473642aec302697cdaceb719a7f8791369
[25/37] powerpc: Refactor permission masks used for __P/__S table and kernel memory flags
        https://git.kernel.org/powerpc/c/a5a08dc90f4513d1a78582ec24b687fad01cc843
[26/37] powerpc/8xx: Use generic permission masks
        https://git.kernel.org/powerpc/c/f9f09b93e80148fc5824afb338c318272abde529
[27/37] powerpc/64s: Use generic permission masks
        https://git.kernel.org/powerpc/c/58f534623c4d8800c2e5d63da9783530848e570c
[28/37] powerpc/nohash: Add _PAGE_WRITE to supplement _PAGE_RW
        https://git.kernel.org/powerpc/c/d20506d4728c3b7408e84d9aececbcb78c3061ee
[29/37] powerpc/nohash: Replace pte_user() by pte_read()
        https://git.kernel.org/powerpc/c/8e9bd41e4ce1001f5b89e4c9a69f870f39d56c12
[30/37] powerpc/e500: Introduce _PAGE_READ and remove _PAGE_USER
        https://git.kernel.org/powerpc/c/48cf93bb168d506a8278a6fb25c2f88c1c93ce6e
[31/37] powerpc/44x: Introduce _PAGE_READ and remove _PAGE_USER
        https://git.kernel.org/powerpc/c/93820bfeefc4a125a6cedd1ee1a956eeb3eb2580
[32/37] powerpc/40x: Introduce _PAGE_READ and remove _PAGE_USER
        https://git.kernel.org/powerpc/c/ed815bd3fe9b14a742e2ae094f7f55f70918dbbc
[33/37] powerpc/32s: Add _PAGE_WRITE to supplement _PAGE_RW
        https://git.kernel.org/powerpc/c/46ebef51fd92f52ba7dca21d3c4332e4127de515
[34/37] powerpc/32s: Introduce _PAGE_READ and remove _PAGE_USER
        https://git.kernel.org/powerpc/c/bac4cffc7c4a009cf0d16f1785a275e0a7715e8d
[35/37] powerpc/ptdump: Display _PAGE_READ and _PAGE_WRITE
        https://git.kernel.org/powerpc/c/ceaba662c06598e52cbe4b90fef6b71b7f965cf9
[36/37] powerpc: Finally remove _PAGE_USER
        https://git.kernel.org/powerpc/c/163a72fa89161b57b05d848aedfbd5103fac9dd7
[37/37] powerpc: Support execute-only on all powerpc
        https://git.kernel.org/powerpc/c/b1fba034a6793e9601d581594a781b46c255471f

cheers

^ permalink raw reply	[flat|nested] 50+ messages in thread

* Re: [PATCH v2 29/37] powerpc/nohash: Replace pte_user() by pte_read()
  2023-09-25 18:31 ` [PATCH v2 29/37] powerpc/nohash: Replace pte_user() by pte_read() Christophe Leroy
@ 2023-10-31 10:15   ` Aneesh Kumar K.V
  2023-11-06 13:21     ` Christophe Leroy
  0 siblings, 1 reply; 50+ messages in thread
From: Aneesh Kumar K.V @ 2023-10-31 10:15 UTC (permalink / raw)
  To: Christophe Leroy, Michael Ellerman, Nicholas Piggin
  Cc: linuxppc-dev, linux-kernel

Christophe Leroy <christophe.leroy@csgroup.eu> writes:

> pte_user() is now only used in pte_access_permitted() to check
> access on vmas. User flag is cleared to make a page unreadable.
>
> So rename it pte_read() and remove pte_user() which isn't used
> anymore.
>
> For the time being it checks _PAGE_USER but in the near futur
> all plateforms will be converted to _PAGE_READ so lets support
> both for now.
>
> Signed-off-by: Christophe Leroy <christophe.leroy@csgroup.eu>
> ---
>  arch/powerpc/include/asm/nohash/32/pte-8xx.h |  7 -------
>  arch/powerpc/include/asm/nohash/pgtable.h    | 13 +++++++------
>  arch/powerpc/mm/ioremap.c                    |  4 ----
>  3 files changed, 7 insertions(+), 17 deletions(-)
>
> diff --git a/arch/powerpc/include/asm/nohash/32/pte-8xx.h b/arch/powerpc/include/asm/nohash/32/pte-8xx.h
> index 62c965a4511a..1ee38befd29a 100644
> --- a/arch/powerpc/include/asm/nohash/32/pte-8xx.h
> +++ b/arch/powerpc/include/asm/nohash/32/pte-8xx.h
> @@ -112,13 +112,6 @@ static inline pte_t pte_mkwrite_novma(pte_t pte)
>  
>  #define pte_mkwrite_novma pte_mkwrite_novma
>  
> -static inline bool pte_user(pte_t pte)
> -{
> -	return !(pte_val(pte) & _PAGE_SH);
> -}
> -
> -#define pte_user pte_user
> -
>  static inline pte_t pte_mkhuge(pte_t pte)
>  {
>  	return __pte(pte_val(pte) | _PAGE_SPS | _PAGE_HUGE);
> diff --git a/arch/powerpc/include/asm/nohash/pgtable.h b/arch/powerpc/include/asm/nohash/pgtable.h
> index ee677162f9e6..aba56fe3b1c6 100644
> --- a/arch/powerpc/include/asm/nohash/pgtable.h
> +++ b/arch/powerpc/include/asm/nohash/pgtable.h
> @@ -160,9 +160,6 @@ static inline int pte_write(pte_t pte)
>  	return pte_val(pte) & _PAGE_WRITE;
>  }
>  #endif
> -#ifndef pte_read
> -static inline int pte_read(pte_t pte)		{ return 1; }
> -#endif
>  static inline int pte_dirty(pte_t pte)		{ return pte_val(pte) & _PAGE_DIRTY; }
>  static inline int pte_special(pte_t pte)	{ return pte_val(pte) & _PAGE_SPECIAL; }
>  static inline int pte_none(pte_t pte)		{ return (pte_val(pte) & ~_PTE_NONE_MASK) == 0; }
> @@ -190,10 +187,14 @@ static inline int pte_young(pte_t pte)
>   * and PTE_64BIT, PAGE_KERNEL_X contains _PAGE_BAP_SR which is also in
>   * _PAGE_USER.  Need to explicitly match _PAGE_BAP_UR bit in that case too.
>   */
> -#ifndef pte_user
> -static inline bool pte_user(pte_t pte)
> +#ifndef pte_read
> +static inline bool pte_read(pte_t pte)
>  {
> +#ifdef _PAGE_READ
> +	return (pte_val(pte) & _PAGE_READ) == _PAGE_READ;
> +#else
>  	return (pte_val(pte) & _PAGE_USER) == _PAGE_USER;
> +#endif
>  }
>  #endif
>  
> @@ -208,7 +209,7 @@ static inline bool pte_access_permitted(pte_t pte, bool write)
>  	 * A read-only access is controlled by _PAGE_USER bit.
>  	 * We have _PAGE_READ set for WRITE and EXECUTE
>  	 */
> -	if (!pte_present(pte) || !pte_user(pte) || !pte_read(pte))
> +	if (!pte_present(pte) || !pte_read(pte))
>  		return false;
>  
>  	if (write && !pte_write(pte))
> diff --git a/arch/powerpc/mm/ioremap.c b/arch/powerpc/mm/ioremap.c
> index 7823c38f09de..7b0afcabd89f 100644
> --- a/arch/powerpc/mm/ioremap.c
> +++ b/arch/powerpc/mm/ioremap.c
> @@ -50,10 +50,6 @@ void __iomem *ioremap_prot(phys_addr_t addr, size_t size, unsigned long flags)
>  	if (pte_write(pte))
>  		pte = pte_mkdirty(pte);
>  
> -	/* we don't want to let _PAGE_USER leak out */
> -	if (WARN_ON(pte_user(pte)))
> -		return NULL;
>

This check is still valid right? I understand that we want to remove
_PAGE_USER. But then loosing this check is ok? 

> -
>  	if (iowa_is_active())
>  		return iowa_ioremap(addr, size, pte_pgprot(pte), caller);
>  	return __ioremap_caller(addr, size, pte_pgprot(pte), caller);
> -- 
> 2.41.0

^ permalink raw reply	[flat|nested] 50+ messages in thread

* Re: [PATCH v2 37/37] powerpc: Support execute-only on all powerpc
  2023-09-25 18:31 ` [PATCH v2 37/37] powerpc: Support execute-only on all powerpc Christophe Leroy
@ 2023-11-02  5:39   ` Aneesh Kumar K.V
  2023-11-06 13:23     ` Christophe Leroy
  0 siblings, 1 reply; 50+ messages in thread
From: Aneesh Kumar K.V @ 2023-11-02  5:39 UTC (permalink / raw)
  To: Christophe Leroy, Michael Ellerman, Nicholas Piggin
  Cc: Kees Cook, linuxppc-dev, linux-kernel, Russell Currey

Christophe Leroy <christophe.leroy@csgroup.eu> writes:

> Introduce PAGE_EXECONLY_X macro which provides exec-only rights.
> The _X may be seen as redundant with the EXECONLY but it helps
> keep consistancy, all macros having the EXEC right have _X.
>
> And put it next to PAGE_NONE as PAGE_EXECONLY_X is
> somehow PAGE_NONE + EXEC just like all other SOMETHING_X are
> just SOMETHING + EXEC.
>
> On book3s/64 PAGE_EXECONLY becomes PAGE_READONLY_X.
>
> On book3s/64, as PAGE_EXECONLY is only valid for Radix add
> VM_READ flag in vm_get_page_prot() for non-Radix.
>
> And update access_error() so that a non exec fault on a VM_EXEC only
> mapping is always invalid, even when the underlying layer don't
> always generate a fault for that.
>
> For 8xx, set PAGE_EXECONLY_X as _PAGE_NA | _PAGE_EXEC.
> For others, only set it as just _PAGE_EXEC
>
> With that change, 8xx, e500 and 44x fully honor execute-only
> protection.
>
> On 40x that is a partial implementation of execute-only. The
> implementation won't be complete because once a TLB has been loaded
> via the Instruction TLB miss handler, it will be possible to read
> the page. But at least it can't be read unless it is executed first.
>
> On 603 MMU, TLB missed are handled by SW and there are separate
> DTLB and ITLB. Execute-only is therefore now supported by not loading
> DTLB when read access is not permitted.
>
> On hash (604) MMU it is more tricky because hash table is common to
> load/store and execute. Nevertheless it is still possible to check
> whether _PAGE_READ is set before loading hash table for a load/store
> access. At least it can't be read unless it is executed first.
>
> Signed-off-by: Christophe Leroy <christophe.leroy@csgroup.eu>
> Cc: Russell Currey <ruscur@russell.cc>
> Cc: Kees Cook <keescook@chromium.org>
> ---
>  arch/powerpc/include/asm/book3s/32/pgtable.h |  2 +-
>  arch/powerpc/include/asm/book3s/64/pgtable.h |  4 +---
>  arch/powerpc/include/asm/nohash/32/pte-8xx.h |  1 +
>  arch/powerpc/include/asm/nohash/pgtable.h    |  2 +-
>  arch/powerpc/include/asm/nohash/pte-e500.h   |  1 +
>  arch/powerpc/include/asm/pgtable-masks.h     |  2 ++
>  arch/powerpc/mm/book3s64/pgtable.c           | 10 ++++------
>  arch/powerpc/mm/fault.c                      |  9 +++++----
>  arch/powerpc/mm/pgtable.c                    |  4 ++--
>  9 files changed, 18 insertions(+), 17 deletions(-)
>
> diff --git a/arch/powerpc/include/asm/book3s/32/pgtable.h b/arch/powerpc/include/asm/book3s/32/pgtable.h
> index 244621c88510..52971ee30717 100644
> --- a/arch/powerpc/include/asm/book3s/32/pgtable.h
> +++ b/arch/powerpc/include/asm/book3s/32/pgtable.h
> @@ -425,7 +425,7 @@ static inline bool pte_access_permitted(pte_t pte, bool write)
>  {
>  	/*
>  	 * A read-only access is controlled by _PAGE_READ bit.
> -	 * We have _PAGE_READ set for WRITE and EXECUTE
> +	 * We have _PAGE_READ set for WRITE
>  	 */
>  	if (!pte_present(pte) || !pte_read(pte))
>  		return false; 
>

Should this now be updated to check for EXEC bit ? 

> diff --git a/arch/powerpc/include/asm/book3s/64/pgtable.h b/arch/powerpc/include/asm/book3s/64/pgtable.h
> index 0fd12bdc7b5e..751b01227e36 100644
> --- a/arch/powerpc/include/asm/book3s/64/pgtable.h
> +++ b/arch/powerpc/include/asm/book3s/64/pgtable.h
> @@ -18,6 +18,7 @@
>  #define _PAGE_WRITE		0x00002 /* write access allowed */
>  #define _PAGE_READ		0x00004	/* read access allowed */
>  #define _PAGE_NA		_PAGE_PRIVILEGED
> +#define _PAGE_NAX		_PAGE_EXEC
>  #define _PAGE_RO		_PAGE_READ
>  #define _PAGE_ROX		(_PAGE_READ | _PAGE_EXEC)
>  #define _PAGE_RW		(_PAGE_READ | _PAGE_WRITE)
> @@ -141,9 +142,6 @@
>  
>  #include <asm/pgtable-masks.h>
>  
> -/* Radix only, Hash uses PAGE_READONLY_X + execute-only pkey instead */
> -#define PAGE_EXECONLY	__pgprot(_PAGE_BASE | _PAGE_EXEC)
> -
>  /* Permission masks used for kernel mappings */
>  #define PAGE_KERNEL	__pgprot(_PAGE_BASE | _PAGE_KERNEL_RW)
>  #define PAGE_KERNEL_NC	__pgprot(_PAGE_BASE_NC | _PAGE_KERNEL_RW | _PAGE_TOLERANT)
> diff --git a/arch/powerpc/include/asm/nohash/32/pte-8xx.h b/arch/powerpc/include/asm/nohash/32/pte-8xx.h
> index 1ee38befd29a..137dc3c84e45 100644
> --- a/arch/powerpc/include/asm/nohash/32/pte-8xx.h
> +++ b/arch/powerpc/include/asm/nohash/32/pte-8xx.h
> @@ -48,6 +48,7 @@
>  
>  #define _PAGE_HUGE	0x0800	/* Copied to L1 PS bit 29 */
>  
> +#define _PAGE_NAX	(_PAGE_NA | _PAGE_EXEC)
>  #define _PAGE_ROX	(_PAGE_RO | _PAGE_EXEC)
>  #define _PAGE_RW	0
>  #define _PAGE_RWX	_PAGE_EXEC
> diff --git a/arch/powerpc/include/asm/nohash/pgtable.h b/arch/powerpc/include/asm/nohash/pgtable.h
> index f922c84b23eb..a50be1de9f83 100644
> --- a/arch/powerpc/include/asm/nohash/pgtable.h
> +++ b/arch/powerpc/include/asm/nohash/pgtable.h
> @@ -203,7 +203,7 @@ static inline bool pte_access_permitted(pte_t pte, bool write)
>  {
>  	/*
>  	 * A read-only access is controlled by _PAGE_READ bit.
> -	 * We have _PAGE_READ set for WRITE and EXECUTE
> +	 * We have _PAGE_READ set for WRITE
>  	 */
>  	if (!pte_present(pte) || !pte_read(pte))
>  		return false;
>


Same here. if so I guess book3s/64 also will need an update?

> diff --git a/arch/powerpc/include/asm/nohash/pte-e500.h b/arch/powerpc/include/asm/nohash/pte-e500.h
> index 31d2c3ea7df8..f516f0b5b7a8 100644
> --- a/arch/powerpc/include/asm/nohash/pte-e500.h
> +++ b/arch/powerpc/include/asm/nohash/pte-e500.h
> @@ -57,6 +57,7 @@
>  #define _PAGE_KERNEL_ROX	(_PAGE_BAP_SR | _PAGE_BAP_SX)
>  
>  #define _PAGE_NA	0
> +#define _PAGE_NAX	_PAGE_BAP_UX
>  #define _PAGE_RO	_PAGE_READ
>  #define _PAGE_ROX	(_PAGE_READ | _PAGE_BAP_UX)
>  #define _PAGE_RW	(_PAGE_READ | _PAGE_WRITE)
> diff --git a/arch/powerpc/include/asm/pgtable-masks.h b/arch/powerpc/include/asm/pgtable-masks.h
> index 808a3b9e8fc0..6e8e2db26a5a 100644
> --- a/arch/powerpc/include/asm/pgtable-masks.h
> +++ b/arch/powerpc/include/asm/pgtable-masks.h
> @@ -4,6 +4,7 @@
>  
>  #ifndef _PAGE_NA
>  #define _PAGE_NA	0
> +#define _PAGE_NAX	_PAGE_EXEC
>  #define _PAGE_RO	_PAGE_READ
>  #define _PAGE_ROX	(_PAGE_READ | _PAGE_EXEC)
>  #define _PAGE_RW	(_PAGE_READ | _PAGE_WRITE)
> @@ -20,6 +21,7 @@
>  
>  /* Permission masks used to generate the __P and __S table */
>  #define PAGE_NONE	__pgprot(_PAGE_BASE | _PAGE_NA)
> +#define PAGE_EXECONLY_X	__pgprot(_PAGE_BASE | _PAGE_NAX)
>  #define PAGE_SHARED	__pgprot(_PAGE_BASE | _PAGE_RW)
>  #define PAGE_SHARED_X	__pgprot(_PAGE_BASE | _PAGE_RWX)
>  #define PAGE_COPY	__pgprot(_PAGE_BASE | _PAGE_RO)
> diff --git a/arch/powerpc/mm/book3s64/pgtable.c b/arch/powerpc/mm/book3s64/pgtable.c
> index 8f8a62d3ff4d..be229290a6a7 100644
> --- a/arch/powerpc/mm/book3s64/pgtable.c
> +++ b/arch/powerpc/mm/book3s64/pgtable.c
> @@ -635,12 +635,10 @@ pgprot_t vm_get_page_prot(unsigned long vm_flags)
>  	unsigned long prot;
>  
>  	/* Radix supports execute-only, but protection_map maps X -> RX */
> -	if (radix_enabled() && ((vm_flags & VM_ACCESS_FLAGS) == VM_EXEC)) {
> -		prot = pgprot_val(PAGE_EXECONLY);
> -	} else {
> -		prot = pgprot_val(protection_map[vm_flags &
> -						 (VM_ACCESS_FLAGS | VM_SHARED)]);
> -	}
> +	if (!radix_enabled() && ((vm_flags & VM_ACCESS_FLAGS) == VM_EXEC))
> +		vm_flags |= VM_READ;
> +
> +	prot = pgprot_val(protection_map[vm_flags & (VM_ACCESS_FLAGS | VM_SHARED)]);
>  
>  	if (vm_flags & VM_SAO)
>  		prot |= _PAGE_SAO;
> diff --git a/arch/powerpc/mm/fault.c b/arch/powerpc/mm/fault.c
> index b1723094d464..9e49ede2bc1c 100644
> --- a/arch/powerpc/mm/fault.c
> +++ b/arch/powerpc/mm/fault.c
> @@ -266,14 +266,15 @@ static bool access_error(bool is_write, bool is_exec, struct vm_area_struct *vma
>  	}
>  
>  	/*
> -	 * VM_READ, VM_WRITE and VM_EXEC all imply read permissions, as
> -	 * defined in protection_map[].  Read faults can only be caused by
> -	 * a PROT_NONE mapping, or with a PROT_EXEC-only mapping on Radix.
> +	 * VM_READ, VM_WRITE and VM_EXEC may imply read permissions, as
> +	 * defined in protection_map[].  In that case Read faults can only be
> +	 * caused by a PROT_NONE mapping. However a non exec access on a
> +	 * VM_EXEC only mapping is invalid anyway, so report it as such.
>  	 */
>  	if (unlikely(!vma_is_accessible(vma)))
>  		return true;
>  
> -	if (unlikely(radix_enabled() && ((vma->vm_flags & VM_ACCESS_FLAGS) == VM_EXEC)))
> +	if ((vma->vm_flags & VM_ACCESS_FLAGS) == VM_EXEC)
>  		return true;
>  
>  	/*
> diff --git a/arch/powerpc/mm/pgtable.c b/arch/powerpc/mm/pgtable.c
> index 781a68c69c2f..79508c1d15d7 100644
> --- a/arch/powerpc/mm/pgtable.c
> +++ b/arch/powerpc/mm/pgtable.c
> @@ -492,7 +492,7 @@ const pgprot_t protection_map[16] = {
>  	[VM_READ]					= PAGE_READONLY,
>  	[VM_WRITE]					= PAGE_COPY,
>  	[VM_WRITE | VM_READ]				= PAGE_COPY,
> -	[VM_EXEC]					= PAGE_READONLY_X,
> +	[VM_EXEC]					= PAGE_EXECONLY_X,
>  	[VM_EXEC | VM_READ]				= PAGE_READONLY_X,
>  	[VM_EXEC | VM_WRITE]				= PAGE_COPY_X,
>  	[VM_EXEC | VM_WRITE | VM_READ]			= PAGE_COPY_X,
> @@ -500,7 +500,7 @@ const pgprot_t protection_map[16] = {
>  	[VM_SHARED | VM_READ]				= PAGE_READONLY,
>  	[VM_SHARED | VM_WRITE]				= PAGE_SHARED,
>  	[VM_SHARED | VM_WRITE | VM_READ]		= PAGE_SHARED,
> -	[VM_SHARED | VM_EXEC]				= PAGE_READONLY_X,
> +	[VM_SHARED | VM_EXEC]				= PAGE_EXECONLY_X,
>  	[VM_SHARED | VM_EXEC | VM_READ]			= PAGE_READONLY_X,
>  	[VM_SHARED | VM_EXEC | VM_WRITE]		= PAGE_SHARED_X,
>  	[VM_SHARED | VM_EXEC | VM_WRITE | VM_READ]	= PAGE_SHARED_X
> -- 
> 2.41.0

^ permalink raw reply	[flat|nested] 50+ messages in thread

* Re: [PATCH v2 29/37] powerpc/nohash: Replace pte_user() by pte_read()
  2023-10-31 10:15   ` Aneesh Kumar K.V
@ 2023-11-06 13:21     ` Christophe Leroy
  2023-11-07 13:34       ` Aneesh Kumar K.V
  0 siblings, 1 reply; 50+ messages in thread
From: Christophe Leroy @ 2023-11-06 13:21 UTC (permalink / raw)
  To: Aneesh Kumar K.V, Michael Ellerman, Nicholas Piggin
  Cc: linuxppc-dev, linux-kernel



Le 31/10/2023 à 11:15, Aneesh Kumar K.V a écrit :
> Christophe Leroy <christophe.leroy@csgroup.eu> writes:
> 
>> pte_user() is now only used in pte_access_permitted() to check
>> access on vmas. User flag is cleared to make a page unreadable.
>>
>> So rename it pte_read() and remove pte_user() which isn't used
>> anymore.
>>
>> For the time being it checks _PAGE_USER but in the near futur
>> all plateforms will be converted to _PAGE_READ so lets support
>> both for now.
>>
>> Signed-off-by: Christophe Leroy <christophe.leroy@csgroup.eu>
>> ---
>>   arch/powerpc/include/asm/nohash/32/pte-8xx.h |  7 -------
>>   arch/powerpc/include/asm/nohash/pgtable.h    | 13 +++++++------
>>   arch/powerpc/mm/ioremap.c                    |  4 ----
>>   3 files changed, 7 insertions(+), 17 deletions(-)
>>
>> diff --git a/arch/powerpc/include/asm/nohash/32/pte-8xx.h b/arch/powerpc/include/asm/nohash/32/pte-8xx.h
>> index 62c965a4511a..1ee38befd29a 100644
>> --- a/arch/powerpc/include/asm/nohash/32/pte-8xx.h
>> +++ b/arch/powerpc/include/asm/nohash/32/pte-8xx.h
>> @@ -112,13 +112,6 @@ static inline pte_t pte_mkwrite_novma(pte_t pte)
>>   
>>   #define pte_mkwrite_novma pte_mkwrite_novma
>>   
>> -static inline bool pte_user(pte_t pte)
>> -{
>> -	return !(pte_val(pte) & _PAGE_SH);
>> -}
>> -
>> -#define pte_user pte_user
>> -
>>   static inline pte_t pte_mkhuge(pte_t pte)
>>   {
>>   	return __pte(pte_val(pte) | _PAGE_SPS | _PAGE_HUGE);
>> diff --git a/arch/powerpc/include/asm/nohash/pgtable.h b/arch/powerpc/include/asm/nohash/pgtable.h
>> index ee677162f9e6..aba56fe3b1c6 100644
>> --- a/arch/powerpc/include/asm/nohash/pgtable.h
>> +++ b/arch/powerpc/include/asm/nohash/pgtable.h
>> @@ -160,9 +160,6 @@ static inline int pte_write(pte_t pte)
>>   	return pte_val(pte) & _PAGE_WRITE;
>>   }
>>   #endif
>> -#ifndef pte_read
>> -static inline int pte_read(pte_t pte)		{ return 1; }
>> -#endif
>>   static inline int pte_dirty(pte_t pte)		{ return pte_val(pte) & _PAGE_DIRTY; }
>>   static inline int pte_special(pte_t pte)	{ return pte_val(pte) & _PAGE_SPECIAL; }
>>   static inline int pte_none(pte_t pte)		{ return (pte_val(pte) & ~_PTE_NONE_MASK) == 0; }
>> @@ -190,10 +187,14 @@ static inline int pte_young(pte_t pte)
>>    * and PTE_64BIT, PAGE_KERNEL_X contains _PAGE_BAP_SR which is also in
>>    * _PAGE_USER.  Need to explicitly match _PAGE_BAP_UR bit in that case too.
>>    */
>> -#ifndef pte_user
>> -static inline bool pte_user(pte_t pte)
>> +#ifndef pte_read
>> +static inline bool pte_read(pte_t pte)
>>   {
>> +#ifdef _PAGE_READ
>> +	return (pte_val(pte) & _PAGE_READ) == _PAGE_READ;
>> +#else
>>   	return (pte_val(pte) & _PAGE_USER) == _PAGE_USER;
>> +#endif
>>   }
>>   #endif
>>   
>> @@ -208,7 +209,7 @@ static inline bool pte_access_permitted(pte_t pte, bool write)
>>   	 * A read-only access is controlled by _PAGE_USER bit.
>>   	 * We have _PAGE_READ set for WRITE and EXECUTE
>>   	 */
>> -	if (!pte_present(pte) || !pte_user(pte) || !pte_read(pte))
>> +	if (!pte_present(pte) || !pte_read(pte))
>>   		return false;
>>   
>>   	if (write && !pte_write(pte))
>> diff --git a/arch/powerpc/mm/ioremap.c b/arch/powerpc/mm/ioremap.c
>> index 7823c38f09de..7b0afcabd89f 100644
>> --- a/arch/powerpc/mm/ioremap.c
>> +++ b/arch/powerpc/mm/ioremap.c
>> @@ -50,10 +50,6 @@ void __iomem *ioremap_prot(phys_addr_t addr, size_t size, unsigned long flags)
>>   	if (pte_write(pte))
>>   		pte = pte_mkdirty(pte);
>>   
>> -	/* we don't want to let _PAGE_USER leak out */
>> -	if (WARN_ON(pte_user(pte)))
>> -		return NULL;
>>
> 
> This check is still valid right? I understand that we want to remove
> _PAGE_USER. But then loosing this check is ok?

Well, we may have to think about it for book3s/64. For all others 
_PAGE_USER is gone and replaced by a check of addresses versus TASK_SIZE.

As ioremap() will map into vmalloc space that address is necesserally 
correct.

> 
>> -
>>   	if (iowa_is_active())
>>   		return iowa_ioremap(addr, size, pte_pgprot(pte), caller);
>>   	return __ioremap_caller(addr, size, pte_pgprot(pte), caller);
>> -- 
>> 2.41.0

^ permalink raw reply	[flat|nested] 50+ messages in thread

* Re: [PATCH v2 37/37] powerpc: Support execute-only on all powerpc
  2023-11-02  5:39   ` Aneesh Kumar K.V
@ 2023-11-06 13:23     ` Christophe Leroy
  2023-11-07  6:15       ` Aneesh Kumar K V
  0 siblings, 1 reply; 50+ messages in thread
From: Christophe Leroy @ 2023-11-06 13:23 UTC (permalink / raw)
  To: Aneesh Kumar K.V, Michael Ellerman, Nicholas Piggin
  Cc: linuxppc-dev, linux-kernel, Kees Cook, Russell Currey



Le 02/11/2023 à 06:39, Aneesh Kumar K.V a écrit :
> Christophe Leroy <christophe.leroy@csgroup.eu> writes:
> 
>> Introduce PAGE_EXECONLY_X macro which provides exec-only rights.
>> The _X may be seen as redundant with the EXECONLY but it helps
>> keep consistancy, all macros having the EXEC right have _X.
>>
>> And put it next to PAGE_NONE as PAGE_EXECONLY_X is
>> somehow PAGE_NONE + EXEC just like all other SOMETHING_X are
>> just SOMETHING + EXEC.
>>
>> On book3s/64 PAGE_EXECONLY becomes PAGE_READONLY_X.
>>
>> On book3s/64, as PAGE_EXECONLY is only valid for Radix add
>> VM_READ flag in vm_get_page_prot() for non-Radix.
>>
>> And update access_error() so that a non exec fault on a VM_EXEC only
>> mapping is always invalid, even when the underlying layer don't
>> always generate a fault for that.
>>
>> For 8xx, set PAGE_EXECONLY_X as _PAGE_NA | _PAGE_EXEC.
>> For others, only set it as just _PAGE_EXEC
>>
>> With that change, 8xx, e500 and 44x fully honor execute-only
>> protection.
>>
>> On 40x that is a partial implementation of execute-only. The
>> implementation won't be complete because once a TLB has been loaded
>> via the Instruction TLB miss handler, it will be possible to read
>> the page. But at least it can't be read unless it is executed first.
>>
>> On 603 MMU, TLB missed are handled by SW and there are separate
>> DTLB and ITLB. Execute-only is therefore now supported by not loading
>> DTLB when read access is not permitted.
>>
>> On hash (604) MMU it is more tricky because hash table is common to
>> load/store and execute. Nevertheless it is still possible to check
>> whether _PAGE_READ is set before loading hash table for a load/store
>> access. At least it can't be read unless it is executed first.
>>
>> Signed-off-by: Christophe Leroy <christophe.leroy@csgroup.eu>
>> Cc: Russell Currey <ruscur@russell.cc>
>> Cc: Kees Cook <keescook@chromium.org>
>> ---
>>   arch/powerpc/include/asm/book3s/32/pgtable.h |  2 +-
>>   arch/powerpc/include/asm/book3s/64/pgtable.h |  4 +---
>>   arch/powerpc/include/asm/nohash/32/pte-8xx.h |  1 +
>>   arch/powerpc/include/asm/nohash/pgtable.h    |  2 +-
>>   arch/powerpc/include/asm/nohash/pte-e500.h   |  1 +
>>   arch/powerpc/include/asm/pgtable-masks.h     |  2 ++
>>   arch/powerpc/mm/book3s64/pgtable.c           | 10 ++++------
>>   arch/powerpc/mm/fault.c                      |  9 +++++----
>>   arch/powerpc/mm/pgtable.c                    |  4 ++--
>>   9 files changed, 18 insertions(+), 17 deletions(-)
>>
>> diff --git a/arch/powerpc/include/asm/book3s/32/pgtable.h b/arch/powerpc/include/asm/book3s/32/pgtable.h
>> index 244621c88510..52971ee30717 100644
>> --- a/arch/powerpc/include/asm/book3s/32/pgtable.h
>> +++ b/arch/powerpc/include/asm/book3s/32/pgtable.h
>> @@ -425,7 +425,7 @@ static inline bool pte_access_permitted(pte_t pte, bool write)
>>   {
>>   	/*
>>   	 * A read-only access is controlled by _PAGE_READ bit.
>> -	 * We have _PAGE_READ set for WRITE and EXECUTE
>> +	 * We have _PAGE_READ set for WRITE
>>   	 */
>>   	if (!pte_present(pte) || !pte_read(pte))
>>   		return false;
>>
> 
> Should this now be updated to check for EXEC bit ?

I don't think so based on what I see in arm64: 
https://elixir.bootlin.com/linux/v6.6/source/arch/arm64/include/asm/pgtable.h#L146

Christophe

^ permalink raw reply	[flat|nested] 50+ messages in thread

* Re: [PATCH v2 37/37] powerpc: Support execute-only on all powerpc
  2023-11-06 13:23     ` Christophe Leroy
@ 2023-11-07  6:15       ` Aneesh Kumar K V
  2023-11-09 17:38         ` Christophe Leroy
  0 siblings, 1 reply; 50+ messages in thread
From: Aneesh Kumar K V @ 2023-11-07  6:15 UTC (permalink / raw)
  To: Christophe Leroy, Michael Ellerman, Nicholas Piggin
  Cc: linuxppc-dev, linux-kernel, Kees Cook, Russell Currey

On 11/6/23 6:53 PM, Christophe Leroy wrote:
> 
> 
> Le 02/11/2023 à 06:39, Aneesh Kumar K.V a écrit :
>> Christophe Leroy <christophe.leroy@csgroup.eu> writes:
>>
>>> Introduce PAGE_EXECONLY_X macro which provides exec-only rights.
>>> The _X may be seen as redundant with the EXECONLY but it helps
>>> keep consistancy, all macros having the EXEC right have _X.
>>>
>>> And put it next to PAGE_NONE as PAGE_EXECONLY_X is
>>> somehow PAGE_NONE + EXEC just like all other SOMETHING_X are
>>> just SOMETHING + EXEC.
>>>
>>> On book3s/64 PAGE_EXECONLY becomes PAGE_READONLY_X.
>>>
>>> On book3s/64, as PAGE_EXECONLY is only valid for Radix add
>>> VM_READ flag in vm_get_page_prot() for non-Radix.
>>>
>>> And update access_error() so that a non exec fault on a VM_EXEC only
>>> mapping is always invalid, even when the underlying layer don't
>>> always generate a fault for that.
>>>
>>> For 8xx, set PAGE_EXECONLY_X as _PAGE_NA | _PAGE_EXEC.
>>> For others, only set it as just _PAGE_EXEC
>>>
>>> With that change, 8xx, e500 and 44x fully honor execute-only
>>> protection.
>>>
>>> On 40x that is a partial implementation of execute-only. The
>>> implementation won't be complete because once a TLB has been loaded
>>> via the Instruction TLB miss handler, it will be possible to read
>>> the page. But at least it can't be read unless it is executed first.
>>>
>>> On 603 MMU, TLB missed are handled by SW and there are separate
>>> DTLB and ITLB. Execute-only is therefore now supported by not loading
>>> DTLB when read access is not permitted.
>>>
>>> On hash (604) MMU it is more tricky because hash table is common to
>>> load/store and execute. Nevertheless it is still possible to check
>>> whether _PAGE_READ is set before loading hash table for a load/store
>>> access. At least it can't be read unless it is executed first.
>>>
>>> Signed-off-by: Christophe Leroy <christophe.leroy@csgroup.eu>
>>> Cc: Russell Currey <ruscur@russell.cc>
>>> Cc: Kees Cook <keescook@chromium.org>
>>> ---
>>>   arch/powerpc/include/asm/book3s/32/pgtable.h |  2 +-
>>>   arch/powerpc/include/asm/book3s/64/pgtable.h |  4 +---
>>>   arch/powerpc/include/asm/nohash/32/pte-8xx.h |  1 +
>>>   arch/powerpc/include/asm/nohash/pgtable.h    |  2 +-
>>>   arch/powerpc/include/asm/nohash/pte-e500.h   |  1 +
>>>   arch/powerpc/include/asm/pgtable-masks.h     |  2 ++
>>>   arch/powerpc/mm/book3s64/pgtable.c           | 10 ++++------
>>>   arch/powerpc/mm/fault.c                      |  9 +++++----
>>>   arch/powerpc/mm/pgtable.c                    |  4 ++--
>>>   9 files changed, 18 insertions(+), 17 deletions(-)
>>>
>>> diff --git a/arch/powerpc/include/asm/book3s/32/pgtable.h b/arch/powerpc/include/asm/book3s/32/pgtable.h
>>> index 244621c88510..52971ee30717 100644
>>> --- a/arch/powerpc/include/asm/book3s/32/pgtable.h
>>> +++ b/arch/powerpc/include/asm/book3s/32/pgtable.h
>>> @@ -425,7 +425,7 @@ static inline bool pte_access_permitted(pte_t pte, bool write)
>>>   {
>>>   	/*
>>>   	 * A read-only access is controlled by _PAGE_READ bit.
>>> -	 * We have _PAGE_READ set for WRITE and EXECUTE
>>> +	 * We have _PAGE_READ set for WRITE
>>>   	 */
>>>   	if (!pte_present(pte) || !pte_read(pte))
>>>   		return false;
>>>
>>
>> Should this now be updated to check for EXEC bit ?
> 
> I don't think so based on what I see in arm64: 
> https://elixir.bootlin.com/linux/v6.6/source/arch/arm64/include/asm/pgtable.h#L146
> 

But then there can be a get_user_pages() (FOLL_GET) on an exec only pte right?
if we are going to access the page data(FOLL_PIN), then yes exec only mapping should
fail for that. But if we using it to do struct page manipulation we need pte_access_permitted
to return true for exec only mapping?


-aneesh



^ permalink raw reply	[flat|nested] 50+ messages in thread

* Re: [PATCH v2 29/37] powerpc/nohash: Replace pte_user() by pte_read()
  2023-11-06 13:21     ` Christophe Leroy
@ 2023-11-07 13:34       ` Aneesh Kumar K.V
  2023-11-09 18:20         ` Christophe Leroy
  0 siblings, 1 reply; 50+ messages in thread
From: Aneesh Kumar K.V @ 2023-11-07 13:34 UTC (permalink / raw)
  To: Christophe Leroy, Michael Ellerman, Nicholas Piggin
  Cc: linuxppc-dev, linux-kernel

Christophe Leroy <christophe.leroy@csgroup.eu> writes:

> Le 31/10/2023 à 11:15, Aneesh Kumar K.V a écrit :
>> Christophe Leroy <christophe.leroy@csgroup.eu> writes:
>> 
>>> pte_user() is now only used in pte_access_permitted() to check
>>> access on vmas. User flag is cleared to make a page unreadable.
>>>
>>> So rename it pte_read() and remove pte_user() which isn't used
>>> anymore.
>>>
>>> For the time being it checks _PAGE_USER but in the near futur
>>> all plateforms will be converted to _PAGE_READ so lets support
>>> both for now.
>>>
>>> Signed-off-by: Christophe Leroy <christophe.leroy@csgroup.eu>
>>> ---
>>>   arch/powerpc/include/asm/nohash/32/pte-8xx.h |  7 -------
>>>   arch/powerpc/include/asm/nohash/pgtable.h    | 13 +++++++------
>>>   arch/powerpc/mm/ioremap.c                    |  4 ----
>>>   3 files changed, 7 insertions(+), 17 deletions(-)
>>>
>>> diff --git a/arch/powerpc/include/asm/nohash/32/pte-8xx.h b/arch/powerpc/include/asm/nohash/32/pte-8xx.h
>>> index 62c965a4511a..1ee38befd29a 100644
>>> --- a/arch/powerpc/include/asm/nohash/32/pte-8xx.h
>>> +++ b/arch/powerpc/include/asm/nohash/32/pte-8xx.h
>>> @@ -112,13 +112,6 @@ static inline pte_t pte_mkwrite_novma(pte_t pte)
>>>   
>>>   #define pte_mkwrite_novma pte_mkwrite_novma
>>>   
>>> -static inline bool pte_user(pte_t pte)
>>> -{
>>> -	return !(pte_val(pte) & _PAGE_SH);
>>> -}
>>> -
>>> -#define pte_user pte_user
>>> -
>>>   static inline pte_t pte_mkhuge(pte_t pte)
>>>   {
>>>   	return __pte(pte_val(pte) | _PAGE_SPS | _PAGE_HUGE);
>>> diff --git a/arch/powerpc/include/asm/nohash/pgtable.h b/arch/powerpc/include/asm/nohash/pgtable.h
>>> index ee677162f9e6..aba56fe3b1c6 100644
>>> --- a/arch/powerpc/include/asm/nohash/pgtable.h
>>> +++ b/arch/powerpc/include/asm/nohash/pgtable.h
>>> @@ -160,9 +160,6 @@ static inline int pte_write(pte_t pte)
>>>   	return pte_val(pte) & _PAGE_WRITE;
>>>   }
>>>   #endif
>>> -#ifndef pte_read
>>> -static inline int pte_read(pte_t pte)		{ return 1; }
>>> -#endif
>>>   static inline int pte_dirty(pte_t pte)		{ return pte_val(pte) & _PAGE_DIRTY; }
>>>   static inline int pte_special(pte_t pte)	{ return pte_val(pte) & _PAGE_SPECIAL; }
>>>   static inline int pte_none(pte_t pte)		{ return (pte_val(pte) & ~_PTE_NONE_MASK) == 0; }
>>> @@ -190,10 +187,14 @@ static inline int pte_young(pte_t pte)
>>>    * and PTE_64BIT, PAGE_KERNEL_X contains _PAGE_BAP_SR which is also in
>>>    * _PAGE_USER.  Need to explicitly match _PAGE_BAP_UR bit in that case too.
>>>    */
>>> -#ifndef pte_user
>>> -static inline bool pte_user(pte_t pte)
>>> +#ifndef pte_read
>>> +static inline bool pte_read(pte_t pte)
>>>   {
>>> +#ifdef _PAGE_READ
>>> +	return (pte_val(pte) & _PAGE_READ) == _PAGE_READ;
>>> +#else
>>>   	return (pte_val(pte) & _PAGE_USER) == _PAGE_USER;
>>> +#endif
>>>   }
>>>   #endif
>>>   
>>> @@ -208,7 +209,7 @@ static inline bool pte_access_permitted(pte_t pte, bool write)
>>>   	 * A read-only access is controlled by _PAGE_USER bit.
>>>   	 * We have _PAGE_READ set for WRITE and EXECUTE
>>>   	 */
>>> -	if (!pte_present(pte) || !pte_user(pte) || !pte_read(pte))
>>> +	if (!pte_present(pte) || !pte_read(pte))
>>>   		return false;
>>>   
>>>   	if (write && !pte_write(pte))
>>> diff --git a/arch/powerpc/mm/ioremap.c b/arch/powerpc/mm/ioremap.c
>>> index 7823c38f09de..7b0afcabd89f 100644
>>> --- a/arch/powerpc/mm/ioremap.c
>>> +++ b/arch/powerpc/mm/ioremap.c
>>> @@ -50,10 +50,6 @@ void __iomem *ioremap_prot(phys_addr_t addr, size_t size, unsigned long flags)
>>>   	if (pte_write(pte))
>>>   		pte = pte_mkdirty(pte);
>>>   
>>> -	/* we don't want to let _PAGE_USER leak out */
>>> -	if (WARN_ON(pte_user(pte)))
>>> -		return NULL;
>>>
>> 
>> This check is still valid right? I understand that we want to remove
>> _PAGE_USER. But then loosing this check is ok?
>
> Well, we may have to think about it for book3s/64. For all others 
> _PAGE_USER is gone and replaced by a check of addresses versus TASK_SIZE.
>
> As ioremap() will map into vmalloc space that address is necesserally 
> correct.
> 
>

We are adding the pte flags check not the map addr check there. Something like this?

diff --git a/arch/powerpc/include/asm/book3s/64/pgtable.h b/arch/powerpc/include/asm/book3s/64/pgtable.h
index 7c7de7b56df0..b053b86e0069 100644
--- a/arch/powerpc/include/asm/book3s/64/pgtable.h
+++ b/arch/powerpc/include/asm/book3s/64/pgtable.h
@@ -1462,5 +1462,11 @@ static inline bool pud_is_leaf(pud_t pud)
 	return !!(pud_raw(pud) & cpu_to_be64(_PAGE_PTE));
 }
 
+#define arch_ioremap_valid_pte arch_ioremap_valid_pte
+static inline bool arch_ioremap_valid_pte(pte_t pte)
+{
+	return !!(pte_raw(pte) & cpu_to_be64(_PAGE_PRIVILEGED));
+}
+
 #endif /* __ASSEMBLY__ */
 #endif /* _ASM_POWERPC_BOOK3S_64_PGTABLE_H_ */
diff --git a/arch/powerpc/include/asm/nohash/32/pte-8xx.h b/arch/powerpc/include/asm/nohash/32/pte-8xx.h
index 137dc3c84e45..7b23d2543528 100644
--- a/arch/powerpc/include/asm/nohash/32/pte-8xx.h
+++ b/arch/powerpc/include/asm/nohash/32/pte-8xx.h
@@ -223,5 +223,11 @@ static inline pte_t ptep_get(pte_t *ptep)
 
 #endif
 
+#define arch_ioremap_valid_pte arch_ioremap_valid_pte
+static inline bool arch_ioremap_valid_pte(pte_t pte)
+{
+	return !!(pte_val(pte) & (_PAGE_SH))
+}
+
 #endif /* __KERNEL__ */
 #endif /*  _ASM_POWERPC_NOHASH_32_PTE_8xx_H */
diff --git a/arch/powerpc/include/asm/nohash/pte-e500.h b/arch/powerpc/include/asm/nohash/pte-e500.h
index f516f0b5b7a8..d31274178aa6 100644
--- a/arch/powerpc/include/asm/nohash/pte-e500.h
+++ b/arch/powerpc/include/asm/nohash/pte-e500.h
@@ -105,6 +105,13 @@ static inline pte_t pte_mkexec(pte_t pte)
 }
 #define pte_mkexec pte_mkexec
 
+#define arch_ioremap_valid_pte arch_ioremap_valid_pte
+static inline bool arch_ioremap_valid_pte(pte_t pte)
+{
+	return !(pte_val(pte) & (_PAGE_BAP_UR | _PAGE_BAP_UW | _PAGE_BAP_UX))
+}
+
+
 #endif /* __ASSEMBLY__ */
 
 #endif /* __KERNEL__ */
diff --git a/arch/powerpc/include/asm/pgtable.h b/arch/powerpc/include/asm/pgtable.h
index 2bfb7dd3b49e..417abe5dcbd8 100644
--- a/arch/powerpc/include/asm/pgtable.h
+++ b/arch/powerpc/include/asm/pgtable.h
@@ -231,6 +231,13 @@ static inline bool arch_supports_memmap_on_memory(unsigned long vmemmap_size)
 
 #endif /* CONFIG_PPC64 */
 
+#ifndef arch_ioremap_valid_pte
+static inline book arch_ioremap_valid_pte(pte_t pte)
+{
+	return true;
+}
+#endif
+
 #endif /* __ASSEMBLY__ */
 
 #endif /* _ASM_POWERPC_PGTABLE_H */
diff --git a/arch/powerpc/mm/ioremap.c b/arch/powerpc/mm/ioremap.c
index 7b0afcabd89f..1a39e698c3d4 100644
--- a/arch/powerpc/mm/ioremap.c
+++ b/arch/powerpc/mm/ioremap.c
@@ -50,6 +50,9 @@ void __iomem *ioremap_prot(phys_addr_t addr, size_t size, unsigned long flags)
 	if (pte_write(pte))
 		pte = pte_mkdirty(pte);
 
+	if (WARN_ON(!arch_ioremap_valid_pte(pte)))
+		return NULL;
+
 	if (iowa_is_active())
 		return iowa_ioremap(addr, size, pte_pgprot(pte), caller);
 	return __ioremap_caller(addr, size, pte_pgprot(pte), caller);
 

^ permalink raw reply related	[flat|nested] 50+ messages in thread

* Re: [PATCH v2 37/37] powerpc: Support execute-only on all powerpc
  2023-11-07  6:15       ` Aneesh Kumar K V
@ 2023-11-09 17:38         ` Christophe Leroy
  0 siblings, 0 replies; 50+ messages in thread
From: Christophe Leroy @ 2023-11-09 17:38 UTC (permalink / raw)
  To: Aneesh Kumar K V, Michael Ellerman, Nicholas Piggin
  Cc: Kees Cook, linux-kernel, linux-mm, Russell Currey, linuxppc-dev,
	Linux ARM



Le 07/11/2023 à 07:15, Aneesh Kumar K V a écrit :
> On 11/6/23 6:53 PM, Christophe Leroy wrote:
>>
>>
>> Le 02/11/2023 à 06:39, Aneesh Kumar K.V a écrit :
>>> Christophe Leroy <christophe.leroy@csgroup.eu> writes:
>>>
>>>> Introduce PAGE_EXECONLY_X macro which provides exec-only rights.
>>>> The _X may be seen as redundant with the EXECONLY but it helps
>>>> keep consistancy, all macros having the EXEC right have _X.
>>>>
>>>> And put it next to PAGE_NONE as PAGE_EXECONLY_X is
>>>> somehow PAGE_NONE + EXEC just like all other SOMETHING_X are
>>>> just SOMETHING + EXEC.
>>>>
>>>> On book3s/64 PAGE_EXECONLY becomes PAGE_READONLY_X.
>>>>
>>>> On book3s/64, as PAGE_EXECONLY is only valid for Radix add
>>>> VM_READ flag in vm_get_page_prot() for non-Radix.
>>>>
>>>> And update access_error() so that a non exec fault on a VM_EXEC only
>>>> mapping is always invalid, even when the underlying layer don't
>>>> always generate a fault for that.
>>>>
>>>> For 8xx, set PAGE_EXECONLY_X as _PAGE_NA | _PAGE_EXEC.
>>>> For others, only set it as just _PAGE_EXEC
>>>>
>>>> With that change, 8xx, e500 and 44x fully honor execute-only
>>>> protection.
>>>>
>>>> On 40x that is a partial implementation of execute-only. The
>>>> implementation won't be complete because once a TLB has been loaded
>>>> via the Instruction TLB miss handler, it will be possible to read
>>>> the page. But at least it can't be read unless it is executed first.
>>>>
>>>> On 603 MMU, TLB missed are handled by SW and there are separate
>>>> DTLB and ITLB. Execute-only is therefore now supported by not loading
>>>> DTLB when read access is not permitted.
>>>>
>>>> On hash (604) MMU it is more tricky because hash table is common to
>>>> load/store and execute. Nevertheless it is still possible to check
>>>> whether _PAGE_READ is set before loading hash table for a load/store
>>>> access. At least it can't be read unless it is executed first.
>>>>
>>>> Signed-off-by: Christophe Leroy <christophe.leroy@csgroup.eu>
>>>> Cc: Russell Currey <ruscur@russell.cc>
>>>> Cc: Kees Cook <keescook@chromium.org>
>>>> ---
>>>>    arch/powerpc/include/asm/book3s/32/pgtable.h |  2 +-
>>>>    arch/powerpc/include/asm/book3s/64/pgtable.h |  4 +---
>>>>    arch/powerpc/include/asm/nohash/32/pte-8xx.h |  1 +
>>>>    arch/powerpc/include/asm/nohash/pgtable.h    |  2 +-
>>>>    arch/powerpc/include/asm/nohash/pte-e500.h   |  1 +
>>>>    arch/powerpc/include/asm/pgtable-masks.h     |  2 ++
>>>>    arch/powerpc/mm/book3s64/pgtable.c           | 10 ++++------
>>>>    arch/powerpc/mm/fault.c                      |  9 +++++----
>>>>    arch/powerpc/mm/pgtable.c                    |  4 ++--
>>>>    9 files changed, 18 insertions(+), 17 deletions(-)
>>>>
>>>> diff --git a/arch/powerpc/include/asm/book3s/32/pgtable.h b/arch/powerpc/include/asm/book3s/32/pgtable.h
>>>> index 244621c88510..52971ee30717 100644
>>>> --- a/arch/powerpc/include/asm/book3s/32/pgtable.h
>>>> +++ b/arch/powerpc/include/asm/book3s/32/pgtable.h
>>>> @@ -425,7 +425,7 @@ static inline bool pte_access_permitted(pte_t pte, bool write)
>>>>    {
>>>>    	/*
>>>>    	 * A read-only access is controlled by _PAGE_READ bit.
>>>> -	 * We have _PAGE_READ set for WRITE and EXECUTE
>>>> +	 * We have _PAGE_READ set for WRITE
>>>>    	 */
>>>>    	if (!pte_present(pte) || !pte_read(pte))
>>>>    		return false;
>>>>
>>>
>>> Should this now be updated to check for EXEC bit ?
>>
>> I don't think so based on what I see in arm64:
>> https://elixir.bootlin.com/linux/v6.6/source/arch/arm64/include/asm/pgtable.h#L146
>>
> 
> But then there can be a get_user_pages() (FOLL_GET) on an exec only pte right?
> if we are going to access the page data(FOLL_PIN), then yes exec only mapping should
> fail for that. But if we using it to do struct page manipulation we need pte_access_permitted
> to return true for exec only mapping?
> 

I don't know enough the details of GUP to understand what you mean. I 
understand you think there is a problem, do you mean ARM64 did it wrong ?

The core mm only has two call sites for pte_access_permitted() which are 
gup_pte_range() and gup_hugepte(). pte_access_permitted() is not 
documented in Documentation/mm/arch_pgtable_helpers.rst

So, what do those two callers expect ?

Christophe

^ permalink raw reply	[flat|nested] 50+ messages in thread

* Re: [PATCH v2 29/37] powerpc/nohash: Replace pte_user() by pte_read()
  2023-11-07 13:34       ` Aneesh Kumar K.V
@ 2023-11-09 18:20         ` Christophe Leroy
  2023-11-13 10:23           ` Aneesh Kumar K.V
  0 siblings, 1 reply; 50+ messages in thread
From: Christophe Leroy @ 2023-11-09 18:20 UTC (permalink / raw)
  To: Aneesh Kumar K.V, Michael Ellerman, Nicholas Piggin
  Cc: linuxppc-dev, linux-kernel



Le 07/11/2023 à 14:34, Aneesh Kumar K.V a écrit :
> Christophe Leroy <christophe.leroy@csgroup.eu> writes:
> 
>> Le 31/10/2023 à 11:15, Aneesh Kumar K.V a écrit :
>>> Christophe Leroy <christophe.leroy@csgroup.eu> writes:
>>>
>>>> pte_user() is now only used in pte_access_permitted() to check
>>>> access on vmas. User flag is cleared to make a page unreadable.
>>>>
>>>> So rename it pte_read() and remove pte_user() which isn't used
>>>> anymore.
>>>>
>>>> For the time being it checks _PAGE_USER but in the near futur
>>>> all plateforms will be converted to _PAGE_READ so lets support
>>>> both for now.
>>>>
>>>> Signed-off-by: Christophe Leroy <christophe.leroy@csgroup.eu>
>>>> ---
>>>>    arch/powerpc/include/asm/nohash/32/pte-8xx.h |  7 -------
>>>>    arch/powerpc/include/asm/nohash/pgtable.h    | 13 +++++++------
>>>>    arch/powerpc/mm/ioremap.c                    |  4 ----
>>>>    3 files changed, 7 insertions(+), 17 deletions(-)
>>>>
>>>> diff --git a/arch/powerpc/include/asm/nohash/32/pte-8xx.h b/arch/powerpc/include/asm/nohash/32/pte-8xx.h
>>>> index 62c965a4511a..1ee38befd29a 100644
>>>> --- a/arch/powerpc/include/asm/nohash/32/pte-8xx.h
>>>> +++ b/arch/powerpc/include/asm/nohash/32/pte-8xx.h
>>>> @@ -112,13 +112,6 @@ static inline pte_t pte_mkwrite_novma(pte_t pte)
>>>>    
>>>>    #define pte_mkwrite_novma pte_mkwrite_novma
>>>>    
>>>> -static inline bool pte_user(pte_t pte)
>>>> -{
>>>> -	return !(pte_val(pte) & _PAGE_SH);
>>>> -}
>>>> -
>>>> -#define pte_user pte_user
>>>> -
>>>>    static inline pte_t pte_mkhuge(pte_t pte)
>>>>    {
>>>>    	return __pte(pte_val(pte) | _PAGE_SPS | _PAGE_HUGE);
>>>> diff --git a/arch/powerpc/include/asm/nohash/pgtable.h b/arch/powerpc/include/asm/nohash/pgtable.h
>>>> index ee677162f9e6..aba56fe3b1c6 100644
>>>> --- a/arch/powerpc/include/asm/nohash/pgtable.h
>>>> +++ b/arch/powerpc/include/asm/nohash/pgtable.h
>>>> @@ -160,9 +160,6 @@ static inline int pte_write(pte_t pte)
>>>>    	return pte_val(pte) & _PAGE_WRITE;
>>>>    }
>>>>    #endif
>>>> -#ifndef pte_read
>>>> -static inline int pte_read(pte_t pte)		{ return 1; }
>>>> -#endif
>>>>    static inline int pte_dirty(pte_t pte)		{ return pte_val(pte) & _PAGE_DIRTY; }
>>>>    static inline int pte_special(pte_t pte)	{ return pte_val(pte) & _PAGE_SPECIAL; }
>>>>    static inline int pte_none(pte_t pte)		{ return (pte_val(pte) & ~_PTE_NONE_MASK) == 0; }
>>>> @@ -190,10 +187,14 @@ static inline int pte_young(pte_t pte)
>>>>     * and PTE_64BIT, PAGE_KERNEL_X contains _PAGE_BAP_SR which is also in
>>>>     * _PAGE_USER.  Need to explicitly match _PAGE_BAP_UR bit in that case too.
>>>>     */
>>>> -#ifndef pte_user
>>>> -static inline bool pte_user(pte_t pte)
>>>> +#ifndef pte_read
>>>> +static inline bool pte_read(pte_t pte)
>>>>    {
>>>> +#ifdef _PAGE_READ
>>>> +	return (pte_val(pte) & _PAGE_READ) == _PAGE_READ;
>>>> +#else
>>>>    	return (pte_val(pte) & _PAGE_USER) == _PAGE_USER;
>>>> +#endif
>>>>    }
>>>>    #endif
>>>>    
>>>> @@ -208,7 +209,7 @@ static inline bool pte_access_permitted(pte_t pte, bool write)
>>>>    	 * A read-only access is controlled by _PAGE_USER bit.
>>>>    	 * We have _PAGE_READ set for WRITE and EXECUTE
>>>>    	 */
>>>> -	if (!pte_present(pte) || !pte_user(pte) || !pte_read(pte))
>>>> +	if (!pte_present(pte) || !pte_read(pte))
>>>>    		return false;
>>>>    
>>>>    	if (write && !pte_write(pte))
>>>> diff --git a/arch/powerpc/mm/ioremap.c b/arch/powerpc/mm/ioremap.c
>>>> index 7823c38f09de..7b0afcabd89f 100644
>>>> --- a/arch/powerpc/mm/ioremap.c
>>>> +++ b/arch/powerpc/mm/ioremap.c
>>>> @@ -50,10 +50,6 @@ void __iomem *ioremap_prot(phys_addr_t addr, size_t size, unsigned long flags)
>>>>    	if (pte_write(pte))
>>>>    		pte = pte_mkdirty(pte);
>>>>    
>>>> -	/* we don't want to let _PAGE_USER leak out */
>>>> -	if (WARN_ON(pte_user(pte)))
>>>> -		return NULL;
>>>>
>>>
>>> This check is still valid right? I understand that we want to remove
>>> _PAGE_USER. But then loosing this check is ok?
>>
>> Well, we may have to think about it for book3s/64. For all others
>> _PAGE_USER is gone and replaced by a check of addresses versus TASK_SIZE.
>>
>> As ioremap() will map into vmalloc space that address is necesserally
>> correct.
>>
>>
> 
> We are adding the pte flags check not the map addr check there. Something like this?

Well, ok, but then why do we want to do that check for ioremap() and not 
for everything else ? vmap() for instance will not perform any such 
check. All it does is to clear the EXEC bit.

As far as I can see, no other architecture does such a check, so why is 
it needed on powerpc at all ?

Regardless, comments below.

> 
> diff --git a/arch/powerpc/include/asm/book3s/64/pgtable.h b/arch/powerpc/include/asm/book3s/64/pgtable.h
> index 7c7de7b56df0..b053b86e0069 100644
> --- a/arch/powerpc/include/asm/book3s/64/pgtable.h
> +++ b/arch/powerpc/include/asm/book3s/64/pgtable.h
> @@ -1462,5 +1462,11 @@ static inline bool pud_is_leaf(pud_t pud)
>   	return !!(pud_raw(pud) & cpu_to_be64(_PAGE_PTE));
>   }
>   
> +#define arch_ioremap_valid_pte arch_ioremap_valid_pte
> +static inline bool arch_ioremap_valid_pte(pte_t pte)
> +{
> +	return !!(pte_raw(pte) & cpu_to_be64(_PAGE_PRIVILEGED));
> +}
> +
>   #endif /* __ASSEMBLY__ */
>   #endif /* _ASM_POWERPC_BOOK3S_64_PGTABLE_H_ */
> diff --git a/arch/powerpc/include/asm/nohash/32/pte-8xx.h b/arch/powerpc/include/asm/nohash/32/pte-8xx.h
> index 137dc3c84e45..7b23d2543528 100644
> --- a/arch/powerpc/include/asm/nohash/32/pte-8xx.h
> +++ b/arch/powerpc/include/asm/nohash/32/pte-8xx.h
> @@ -223,5 +223,11 @@ static inline pte_t ptep_get(pte_t *ptep)
>   
>   #endif
>   
> +#define arch_ioremap_valid_pte arch_ioremap_valid_pte
> +static inline bool arch_ioremap_valid_pte(pte_t pte)
> +{
> +	return !!(pte_val(pte) & (_PAGE_SH))
> +}
> +

_PAGE_SH bit means the page is shared hence is valid for all PIDs. It 
was used as a trick for pte_user() because all kernel pages have SH bit 
set while user pages have SH bit unset, but clearing SH bit doesn't make 
the page become a user page. User pages are defined by _PMD_USER flag at 
PMD level.

So I think this can be dropped.

If we wanted to be really strict with the verification, we should check 
that the PPP bits won't contain something odd, because some unused 
combinations may provide user access to pages located in PMDs not having 
_PMD_USER. But is that really worth it ?

In case we want that check:
- PAGE_NA is 0x200
- PAGE_RO is 0x600
- PAGE_RW is 0x000
Last possible combination is 0x400, that one will set it RW for 
supervisor + RO for user.


>   #endif /* __KERNEL__ */
>   #endif /*  _ASM_POWERPC_NOHASH_32_PTE_8xx_H */
> diff --git a/arch/powerpc/include/asm/nohash/pte-e500.h b/arch/powerpc/include/asm/nohash/pte-e500.h
> index f516f0b5b7a8..d31274178aa6 100644
> --- a/arch/powerpc/include/asm/nohash/pte-e500.h
> +++ b/arch/powerpc/include/asm/nohash/pte-e500.h
> @@ -105,6 +105,13 @@ static inline pte_t pte_mkexec(pte_t pte)
>   }
>   #define pte_mkexec pte_mkexec
>   
> +#define arch_ioremap_valid_pte arch_ioremap_valid_pte
> +static inline bool arch_ioremap_valid_pte(pte_t pte)
> +{
> +	return !(pte_val(pte) & (_PAGE_BAP_UR | _PAGE_BAP_UW | _PAGE_BAP_UX))
> +}
> +
> +
>   #endif /* __ASSEMBLY__ */
>   
>   #endif /* __KERNEL__ */
> diff --git a/arch/powerpc/include/asm/pgtable.h b/arch/powerpc/include/asm/pgtable.h
> index 2bfb7dd3b49e..417abe5dcbd8 100644
> --- a/arch/powerpc/include/asm/pgtable.h
> +++ b/arch/powerpc/include/asm/pgtable.h
> @@ -231,6 +231,13 @@ static inline bool arch_supports_memmap_on_memory(unsigned long vmemmap_size)
>   
>   #endif /* CONFIG_PPC64 */
>   
> +#ifndef arch_ioremap_valid_pte
> +static inline book arch_ioremap_valid_pte(pte_t pte)
> +{
> +	return true;
> +}
> +#endif
> +
>   #endif /* __ASSEMBLY__ */
>   
>   #endif /* _ASM_POWERPC_PGTABLE_H */
> diff --git a/arch/powerpc/mm/ioremap.c b/arch/powerpc/mm/ioremap.c
> index 7b0afcabd89f..1a39e698c3d4 100644
> --- a/arch/powerpc/mm/ioremap.c
> +++ b/arch/powerpc/mm/ioremap.c
> @@ -50,6 +50,9 @@ void __iomem *ioremap_prot(phys_addr_t addr, size_t size, unsigned long flags)
>   	if (pte_write(pte))
>   		pte = pte_mkdirty(pte);
>   
> +	if (WARN_ON(!arch_ioremap_valid_pte(pte)))
> +		return NULL;
> +
>   	if (iowa_is_active())
>   		return iowa_ioremap(addr, size, pte_pgprot(pte), caller);
>   	return __ioremap_caller(addr, size, pte_pgprot(pte), caller);
>   

^ permalink raw reply	[flat|nested] 50+ messages in thread

* Re: [PATCH v2 29/37] powerpc/nohash: Replace pte_user() by pte_read()
  2023-11-09 18:20         ` Christophe Leroy
@ 2023-11-13 10:23           ` Aneesh Kumar K.V
  2023-11-23 15:55             ` Christophe Leroy
  0 siblings, 1 reply; 50+ messages in thread
From: Aneesh Kumar K.V @ 2023-11-13 10:23 UTC (permalink / raw)
  To: Christophe Leroy, Michael Ellerman, Nicholas Piggin
  Cc: linuxppc-dev, linux-kernel

Christophe Leroy <christophe.leroy@csgroup.eu> writes:

> Le 07/11/2023 à 14:34, Aneesh Kumar K.V a écrit :
>> Christophe Leroy <christophe.leroy@csgroup.eu> writes:
>> 
>>> Le 31/10/2023 à 11:15, Aneesh Kumar K.V a écrit :
>>>> Christophe Leroy <christophe.leroy@csgroup.eu> writes:

....

>>
>> 
>> We are adding the pte flags check not the map addr check there. Something like this?
>
> Well, ok, but then why do we want to do that check for ioremap() and not 
> for everything else ? vmap() for instance will not perform any such 
> check. All it does is to clear the EXEC bit.
>
> As far as I can see, no other architecture does such a check, so why is 
> it needed on powerpc at all ?
>
> Regardless, comments below.
>

Looking at ioremap_prot() I am not clear whether we can really use the
flag value argument as is. For ex: x86 does 

pgprot2cachemode(__pgprot(prot_val))

I see that we use ioremap_prot() for generic_access_phys() and with
/dev/mem and __access_remote_vm() we can get called with a user pte
mapping prot flags? 

If such an prot value can be observed then the original change to clear
EXEC and mark it privileged is required?

	/* we don't want to let _PAGE_USER and _PAGE_EXEC leak out */
	pte = pte_exprotect(pte);
	pte = pte_mkprivileged(pte);


We already handle exec in pgprot_nx() and we need add back
pte_mkprivileged()? 


-aneesh

^ permalink raw reply	[flat|nested] 50+ messages in thread

* Re: [PATCH v2 29/37] powerpc/nohash: Replace pte_user() by pte_read()
  2023-11-13 10:23           ` Aneesh Kumar K.V
@ 2023-11-23 15:55             ` Christophe Leroy
  0 siblings, 0 replies; 50+ messages in thread
From: Christophe Leroy @ 2023-11-23 15:55 UTC (permalink / raw)
  To: Aneesh Kumar K.V, Michael Ellerman, Nicholas Piggin
  Cc: linuxppc-dev, linux-kernel



Le 13/11/2023 à 11:23, Aneesh Kumar K.V a écrit :
> Christophe Leroy <christophe.leroy@csgroup.eu> writes:
> 
>> Le 07/11/2023 à 14:34, Aneesh Kumar K.V a écrit :
>>> Christophe Leroy <christophe.leroy@csgroup.eu> writes:
>>>
>>>> Le 31/10/2023 à 11:15, Aneesh Kumar K.V a écrit :
>>>>> Christophe Leroy <christophe.leroy@csgroup.eu> writes:
> 
> ....
> 
>>>
>>>
>>> We are adding the pte flags check not the map addr check there. Something like this?
>>
>> Well, ok, but then why do we want to do that check for ioremap() and not
>> for everything else ? vmap() for instance will not perform any such
>> check. All it does is to clear the EXEC bit.
>>
>> As far as I can see, no other architecture does such a check, so why is
>> it needed on powerpc at all ?
>>
>> Regardless, comments below.
>>
> 
> Looking at ioremap_prot() I am not clear whether we can really use the
> flag value argument as is. For ex: x86 does
> 
> pgprot2cachemode(__pgprot(prot_val))
> 
> I see that we use ioremap_prot() for generic_access_phys() and with
> /dev/mem and __access_remote_vm() we can get called with a user pte
> mapping prot flags?

Do you think so ?

If I understand correctly, in those cases ioremap_prot() is called with 
prot flags as returned by the call to phys_mem_access_prot().

> 
> If such an prot value can be observed then the original change to clear
> EXEC and mark it privileged is required?
> 
> 	/* we don't want to let _PAGE_USER and _PAGE_EXEC leak out */
> 	pte = pte_exprotect(pte);
> 	pte = pte_mkprivileged(pte);
> 
> 
> We already handle exec in pgprot_nx() and we need add back
> pte_mkprivileged()?

If this is the case for powerpc that's likely the case for most 
architectures. Should we change pgprot_nx() to pgprot_nxu() or have a 
pgprot_nu() in addition ?

Christophe

^ permalink raw reply	[flat|nested] 50+ messages in thread

end of thread, other threads:[~2023-11-23 15:56 UTC | newest]

Thread overview: 50+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-09-25 18:31 [PATCH v2 00/37] Implement execute-only protection on powerpc Christophe Leroy
2023-09-25 18:31 ` [PATCH v2 01/37] powerpc/8xx: Fix pte_access_permitted() for PAGE_NONE Christophe Leroy
2023-09-25 18:31 ` [PATCH v2 02/37] powerpc/64e: Fix wrong test in __ptep_test_and_clear_young() Christophe Leroy
2023-09-25 18:31 ` [PATCH v2 03/37] powerpc/40x: Remove stale PTE_ATOMIC_UPDATES macro Christophe Leroy
2023-09-25 18:31 ` [PATCH v2 04/37] powerpc: Remove pte_ERROR() Christophe Leroy
2023-09-25 18:31 ` [PATCH v2 05/37] powerpc: Deduplicate prototypes of ptep_set_access_flags() and phys_mem_access_prot() Christophe Leroy
2023-09-25 18:31 ` [PATCH v2 06/37] powerpc: Refactor update_mmu_cache_range() Christophe Leroy
2023-09-25 18:31 ` [PATCH v2 07/37] powerpc: Untangle fixmap.h and pgtable.h and mmu.h Christophe Leroy
2023-09-25 18:31 ` [PATCH v2 08/37] powerpc/nohash: Remove {pte/pmd}_protnone() Christophe Leroy
2023-09-25 18:31 ` [PATCH v2 09/37] powerpc/nohash: Refactor declaration of {map/unmap}_kernel_page() Christophe Leroy
2023-09-25 18:31 ` [PATCH v2 10/37] powerpc/nohash: Move 8xx version of pte_update() into pte-8xx.h Christophe Leroy
2023-09-25 18:31 ` [PATCH v2 11/37] powerpc/nohash: Replace #ifdef CONFIG_44x by IS_ENABLED(CONFIG_44x) in pgtable.h Christophe Leroy
2023-09-25 18:31 ` [PATCH v2 12/37] powerpc/nohash: Refactor pte_update() Christophe Leroy
2023-09-25 18:31 ` [PATCH v2 13/37] powerpc/nohash: Refactor checking of no-change in pte_update() Christophe Leroy
2023-09-25 18:31 ` [PATCH v2 14/37] powerpc/nohash: Deduplicate _PAGE_CHG_MASK Christophe Leroy
2023-09-25 18:31 ` [PATCH v2 15/37] powerpc/nohash: Deduplicate pte helpers Christophe Leroy
2023-09-25 18:31 ` [PATCH v2 16/37] powerpc/nohash: Refactor ptep_test_and_clear_young() Christophe Leroy
2023-09-25 18:31 ` [PATCH v2 17/37] powerpc/nohash: Deduplicate ptep_set_wrprotect() and ptep_get_and_clear() Christophe Leroy
2023-09-25 18:31 ` [PATCH v2 18/37] powerpc/nohash: Refactor pte_clear() Christophe Leroy
2023-09-25 18:31 ` [PATCH v2 19/37] powerpc/nohash: Refactor __ptep_set_access_flags() Christophe Leroy
2023-09-25 18:31 ` [PATCH v2 20/37] powerpc/e500: Simplify pte_mkexec() Christophe Leroy
2023-09-25 18:31 ` [PATCH v2 21/37] powerpc: Implement and use pgprot_nx() Christophe Leroy
2023-09-25 18:31 ` [PATCH v2 22/37] powerpc: Fail ioremap() instead of silently ignoring flags when PAGE_USER is set Christophe Leroy
2023-09-25 18:31 ` [PATCH v2 23/37] powerpc: Remove pte_mkuser() and pte_mkpriviledged() Christophe Leroy
2023-09-25 18:31 ` [PATCH v2 24/37] powerpc: Rely on address instead of pte_user() Christophe Leroy
2023-09-25 18:31 ` [PATCH v2 25/37] powerpc: Refactor permission masks used for __P/__S table and kernel memory flags Christophe Leroy
2023-09-25 18:31 ` [PATCH v2 26/37] powerpc/8xx: Use generic permission masks Christophe Leroy
2023-09-25 18:31 ` [PATCH v2 27/37] powerpc/64s: " Christophe Leroy
2023-09-25 18:31 ` [PATCH v2 28/37] powerpc/nohash: Add _PAGE_WRITE to supplement _PAGE_RW Christophe Leroy
2023-09-25 18:31 ` [PATCH v2 29/37] powerpc/nohash: Replace pte_user() by pte_read() Christophe Leroy
2023-10-31 10:15   ` Aneesh Kumar K.V
2023-11-06 13:21     ` Christophe Leroy
2023-11-07 13:34       ` Aneesh Kumar K.V
2023-11-09 18:20         ` Christophe Leroy
2023-11-13 10:23           ` Aneesh Kumar K.V
2023-11-23 15:55             ` Christophe Leroy
2023-09-25 18:31 ` [PATCH v2 30/37] powerpc/e500: Introduce _PAGE_READ and remove _PAGE_USER Christophe Leroy
2023-09-25 18:31 ` [PATCH v2 31/37] powerpc/44x: " Christophe Leroy
2023-09-25 18:31 ` [PATCH v2 32/37] powerpc/40x: " Christophe Leroy
2023-09-25 18:31 ` [PATCH v2 33/37] powerpc/32s: Add _PAGE_WRITE to supplement _PAGE_RW Christophe Leroy
2023-09-25 18:31 ` [PATCH v2 34/37] powerpc/32s: Introduce _PAGE_READ and remove _PAGE_USER Christophe Leroy
2023-09-25 18:31 ` [PATCH v2 35/37] powerpc/ptdump: Display _PAGE_READ and _PAGE_WRITE Christophe Leroy
2023-09-25 18:31 ` [PATCH v2 36/37] powerpc: Finally remove _PAGE_USER Christophe Leroy
2023-09-25 18:31 ` [PATCH v2 37/37] powerpc: Support execute-only on all powerpc Christophe Leroy
2023-11-02  5:39   ` Aneesh Kumar K.V
2023-11-06 13:23     ` Christophe Leroy
2023-11-07  6:15       ` Aneesh Kumar K V
2023-11-09 17:38         ` Christophe Leroy
2023-10-15 10:00 ` (subset) [PATCH v2 00/37] Implement execute-only protection on powerpc Michael Ellerman
2023-10-27  9:59 ` Michael Ellerman

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).