diff mbox series

[v2,5/6] treewide: Add a function to change page permissions

Message ID 20250220135506.151894-6-ilias.apalodimas@linaro.org
State New
Headers show
Series Fix page permission on arm64 architectures | expand

Commit Message

Ilias Apalodimas Feb. 20, 2025, 1:54 p.m. UTC
For armv8 we are adding proper page permissions for the relocated U-Boot
binary. Add a weak function that can be used across architectures to change
the page permissions

Tested-by: Neil Armstrong <neil.armstrong@linaro.org> # on AML-S905X-CC
Signed-off-by: Ilias Apalodimas <ilias.apalodimas@linaro.org>
---
 arch/arc/lib/cache.c           |  6 ++++++
 arch/arm/cpu/arm926ejs/cache.c |  6 ++++++
 arch/arm/cpu/armv7/cache_v7.c  |  6 ++++++
 arch/arm/cpu/armv7m/cache.c    |  6 ++++++
 arch/arm/cpu/armv8/cache_v8.c  | 25 +++++++++++++++++++++++++
 arch/arm/lib/cache.c           |  6 ++++++
 arch/m68k/lib/cache.c          |  6 ++++++
 arch/nios2/lib/cache.c         |  6 ++++++
 arch/powerpc/lib/cache.c       |  6 ++++++
 arch/riscv/lib/cache.c         |  6 ++++++
 arch/sh/cpu/sh4/cache.c        |  6 ++++++
 arch/xtensa/lib/cache.c        |  6 ++++++
 include/cpu_func.h             | 17 +++++++++++++++++
 13 files changed, 108 insertions(+)

Comments

Richard Henderson Feb. 20, 2025, 6:32 p.m. UTC | #1
On 2/20/25 05:54, Ilias Apalodimas wrote:
> +++ b/include/cpu_func.h
> @@ -69,6 +69,23 @@ void flush_dcache_range(unsigned long start, unsigned long stop);
>   void invalidate_dcache_range(unsigned long start, unsigned long stop);
>   void invalidate_dcache_all(void);
>   void invalidate_icache_all(void);
> +
> +enum pgprot_attrs {
> +	MMU_ATTR_RO,
> +	MMU_ATTR_RX,
> +	MMU_ATTR_RW,
> +};
> +
> +/** pgprot_set_attrs() - Set page table permissions
> + *
> + * @addr: Physical address start
> + * @size: size of memory to change
> + * @perm: New permissions
> + *
> + * Return: 0 on success, error otherwise.
> + **/
> +int pgprot_set_attrs(phys_addr_t addr, size_t size, u64 perm);

Why do you not use the enum for 'perm'?
That's certainly the API you're expecting...


r~
Ilias Apalodimas Feb. 20, 2025, 6:37 p.m. UTC | #2
Hi Richard,

On Thu, 20 Feb 2025 at 20:32, Richard Henderson
<richard.henderson@linaro.org> wrote:
>
> On 2/20/25 05:54, Ilias Apalodimas wrote:
> > +++ b/include/cpu_func.h
> > @@ -69,6 +69,23 @@ void flush_dcache_range(unsigned long start, unsigned long stop);
> >   void invalidate_dcache_range(unsigned long start, unsigned long stop);
> >   void invalidate_dcache_all(void);
> >   void invalidate_icache_all(void);
> > +
> > +enum pgprot_attrs {
> > +     MMU_ATTR_RO,
> > +     MMU_ATTR_RX,
> > +     MMU_ATTR_RW,
> > +};
> > +
> > +/** pgprot_set_attrs() - Set page table permissions
> > + *
> > + * @addr: Physical address start
> > + * @size: size of memory to change
> > + * @perm: New permissions
> > + *
> > + * Return: 0 on success, error otherwise.
> > + **/
> > +int pgprot_set_attrs(phys_addr_t addr, size_t size, u64 perm);
>
> Why do you not use the enum for 'perm'?
> That's certainly the API you're expecting...

Ah good catch. On the original RFC I didn't have the enum. Instead I
had raw values of 1,2,3.
I switched it to a proper enum for v1, but missed the function argument.

Thanks
/Ilias

>
>
> r~
diff mbox series

Patch

diff --git a/arch/arc/lib/cache.c b/arch/arc/lib/cache.c
index 5169fc627fa5..2f8b14f77b55 100644
--- a/arch/arc/lib/cache.c
+++ b/arch/arc/lib/cache.c
@@ -8,6 +8,7 @@ 
 #include <asm/global_data.h>
 #include <linux/bitops.h>
 #include <linux/compiler.h>
+#include <linux/errno.h>
 #include <linux/kernel.h>
 #include <linux/log2.h>
 #include <asm/arcregs.h>
@@ -819,3 +820,8 @@  void sync_n_cleanup_cache_all(void)
 
 	__ic_entire_invalidate();
 }
+
+int __weak pgprot_set_attrs(phys_addr_t addr, size_t size, u64 perm)
+{
+	return -ENOSYS;
+}
diff --git a/arch/arm/cpu/arm926ejs/cache.c b/arch/arm/cpu/arm926ejs/cache.c
index 5b87a3af91b2..6051fd47c449 100644
--- a/arch/arm/cpu/arm926ejs/cache.c
+++ b/arch/arm/cpu/arm926ejs/cache.c
@@ -5,6 +5,7 @@ 
  */
 #include <cpu_func.h>
 #include <asm/cache.h>
+#include <linux/errno.h>
 #include <linux/types.h>
 
 #if !CONFIG_IS_ENABLED(SYS_DCACHE_OFF)
@@ -88,3 +89,8 @@  void enable_caches(void)
 	dcache_enable();
 #endif
 }
+
+int __weak pgprot_set_attrs(phys_addr_t addr, size_t size, u64 perm)
+{
+	return -ENOSYS;
+}
diff --git a/arch/arm/cpu/armv7/cache_v7.c b/arch/arm/cpu/armv7/cache_v7.c
index d11420d2fdd0..937b32a7f136 100644
--- a/arch/arm/cpu/armv7/cache_v7.c
+++ b/arch/arm/cpu/armv7/cache_v7.c
@@ -6,6 +6,7 @@ 
  */
 #include <cpu_func.h>
 #include <asm/cache.h>
+#include <linux/errno.h>
 #include <linux/types.h>
 #include <asm/armv7.h>
 #include <asm/utils.h>
@@ -209,3 +210,8 @@  __weak void v7_outer_cache_flush_all(void) {}
 __weak void v7_outer_cache_inval_all(void) {}
 __weak void v7_outer_cache_flush_range(u32 start, u32 end) {}
 __weak void v7_outer_cache_inval_range(u32 start, u32 end) {}
+
+int __weak pgprot_set_attrs(phys_addr_t addr, size_t size, u64 perm)
+{
+	return -ENOSYS;
+}
diff --git a/arch/arm/cpu/armv7m/cache.c b/arch/arm/cpu/armv7m/cache.c
index b6d08b7aad73..b16a9c8f723b 100644
--- a/arch/arm/cpu/armv7m/cache.c
+++ b/arch/arm/cpu/armv7m/cache.c
@@ -11,6 +11,7 @@ 
 #include <asm/cache.h>
 #include <asm/io.h>
 #include <linux/bitops.h>
+#include <linux/errno.h>
 
 /* Cache maintenance operation registers */
 
@@ -370,3 +371,8 @@  void enable_caches(void)
 	dcache_enable();
 #endif
 }
+
+int __weak pgprot_set_attrs(phys_addr_t addr, size_t size, u64 perm)
+{
+	return -ENOSYS;
+}
diff --git a/arch/arm/cpu/armv8/cache_v8.c b/arch/arm/cpu/armv8/cache_v8.c
index 670379e17b7a..b6ea7efc7b75 100644
--- a/arch/arm/cpu/armv8/cache_v8.c
+++ b/arch/arm/cpu/armv8/cache_v8.c
@@ -14,6 +14,7 @@ 
 #include <asm/global_data.h>
 #include <asm/system.h>
 #include <asm/armv8/mmu.h>
+#include <linux/errno.h>
 
 DECLARE_GLOBAL_DATA_PTR;
 
@@ -1028,6 +1029,30 @@  skip_break:
 	__asm_invalidate_tlb_all();
 }
 
+int pgprot_set_attrs(phys_addr_t addr, size_t size, u64 perm)
+{
+	u64 attrs = PTE_BLOCK_MEMTYPE(MT_NORMAL) | PTE_BLOCK_INNER_SHARE | PTE_TYPE_VALID;
+
+	switch (perm) {
+	case MMU_ATTR_RO:
+		attrs |= PTE_BLOCK_PXN | PTE_BLOCK_UXN | PTE_BLOCK_RO;
+		break;
+	case MMU_ATTR_RX:
+		attrs |= PTE_BLOCK_RO;
+		break;
+	case MMU_ATTR_RW:
+		attrs |= PTE_BLOCK_PXN | PTE_BLOCK_UXN;
+		break;
+	default:
+		log_err("Unknown attribute %llx\n", perm);
+		return -EINVAL;
+	}
+
+	mmu_change_region_attr(addr, size, attrs, false);
+
+	return 0;
+}
+
 #else	/* !CONFIG_IS_ENABLED(SYS_DCACHE_OFF) */
 
 /*
diff --git a/arch/arm/lib/cache.c b/arch/arm/lib/cache.c
index 516754caeaf9..d4f1528b453d 100644
--- a/arch/arm/lib/cache.c
+++ b/arch/arm/lib/cache.c
@@ -10,6 +10,7 @@ 
 #include <malloc.h>
 #include <asm/cache.h>
 #include <asm/global_data.h>
+#include <linux/errno.h>
 
 DECLARE_GLOBAL_DATA_PTR;
 
@@ -170,3 +171,8 @@  __weak int arm_reserve_mmu(void)
 
 	return 0;
 }
+
+int __weak pgprot_set_attrs(phys_addr_t addr, size_t size, u64 perm)
+{
+	return -ENOSYS;
+}
diff --git a/arch/m68k/lib/cache.c b/arch/m68k/lib/cache.c
index 370ad40f1423..fce852db2988 100644
--- a/arch/m68k/lib/cache.c
+++ b/arch/m68k/lib/cache.c
@@ -8,6 +8,7 @@ 
 #include <cpu_func.h>
 #include <asm/immap.h>
 #include <asm/cache.h>
+#include <linux/errno.h>
 
 volatile int *cf_icache_status = (int *)ICACHE_STATUS;
 volatile int *cf_dcache_status = (int *)DCACHE_STATUS;
@@ -151,3 +152,8 @@  __weak void flush_dcache_range(unsigned long start, unsigned long stop)
 {
 	/* An empty stub, real implementation should be in platform code */
 }
+
+int __weak pgprot_set_attrs(phys_addr_t addr, size_t size, u64 perm)
+{
+	return -ENOSYS;
+}
diff --git a/arch/nios2/lib/cache.c b/arch/nios2/lib/cache.c
index 8f543f2a2f26..70f258a1760b 100644
--- a/arch/nios2/lib/cache.c
+++ b/arch/nios2/lib/cache.c
@@ -8,6 +8,7 @@ 
 #include <cpu_func.h>
 #include <asm/cache.h>
 #include <asm/global_data.h>
+#include <linux/errno.h>
 
 DECLARE_GLOBAL_DATA_PTR;
 
@@ -127,3 +128,8 @@  void dcache_disable(void)
 {
 	flush_dcache_all();
 }
+
+int __weak pgprot_set_attrs(phys_addr_t addr, size_t size, u64 perm)
+{
+	return -ENOSYS;
+}
diff --git a/arch/powerpc/lib/cache.c b/arch/powerpc/lib/cache.c
index a9cd7b8d30ac..b434fbc4b4a5 100644
--- a/arch/powerpc/lib/cache.c
+++ b/arch/powerpc/lib/cache.c
@@ -8,6 +8,7 @@ 
 #include <stdio.h>
 #include <asm/cache.h>
 #include <watchdog.h>
+#include <linux/errno.h>
 
 static ulong maybe_watchdog_reset(ulong flushed)
 {
@@ -58,3 +59,8 @@  void invalidate_icache_all(void)
 {
 	puts("No arch specific invalidate_icache_all available!\n");
 }
+
+int __weak pgprot_set_attrs(phys_addr_t addr, size_t size, u64 perm)
+{
+	return -ENOSYS;
+}
diff --git a/arch/riscv/lib/cache.c b/arch/riscv/lib/cache.c
index 71e4937ab542..d3ec9d460259 100644
--- a/arch/riscv/lib/cache.c
+++ b/arch/riscv/lib/cache.c
@@ -8,6 +8,7 @@ 
 #include <dm.h>
 #include <asm/insn-def.h>
 #include <linux/const.h>
+#include <linux/errno.h>
 
 #define CBO_INVAL(base)						\
 	INSN_I(OPCODE_MISC_MEM, FUNC3(2), __RD(0),		\
@@ -151,3 +152,8 @@  __weak void enable_caches(void)
 	if (!zicbom_block_size)
 		log_debug("Zicbom not initialized.\n");
 }
+
+int __weak pgprot_set_attrs(phys_addr_t addr, size_t size, u64 perm)
+{
+	return -ENOSYS;
+}
diff --git a/arch/sh/cpu/sh4/cache.c b/arch/sh/cpu/sh4/cache.c
index 99acc5999652..4e6751bfd2f5 100644
--- a/arch/sh/cpu/sh4/cache.c
+++ b/arch/sh/cpu/sh4/cache.c
@@ -11,6 +11,7 @@ 
 #include <asm/io.h>
 #include <asm/processor.h>
 #include <asm/system.h>
+#include <linux/errno.h>
 
 #define CACHE_VALID       1
 #define CACHE_UPDATED     2
@@ -126,3 +127,8 @@  int dcache_status(void)
 {
 	return 0;
 }
+
+int __weak pgprot_set_attrs(phys_addr_t addr, size_t size, u64 perm)
+{
+	return -ENOSYS;
+}
diff --git a/arch/xtensa/lib/cache.c b/arch/xtensa/lib/cache.c
index e6a7f6827fc2..17e1e21f28b9 100644
--- a/arch/xtensa/lib/cache.c
+++ b/arch/xtensa/lib/cache.c
@@ -6,6 +6,7 @@ 
 
 #include <cpu_func.h>
 #include <asm/cache.h>
+#include <linux/errno.h>
 
 /*
  * We currently run always with caches enabled when running from memory.
@@ -57,3 +58,8 @@  void invalidate_icache_all(void)
 {
 	__invalidate_icache_all();
 }
+
+int __weak pgprot_set_attrs(phys_addr_t addr, size_t size, u64 perm)
+{
+	return -ENOSYS;
+}
diff --git a/include/cpu_func.h b/include/cpu_func.h
index 7e81c4364a73..ed21bf71293f 100644
--- a/include/cpu_func.h
+++ b/include/cpu_func.h
@@ -69,6 +69,23 @@  void flush_dcache_range(unsigned long start, unsigned long stop);
 void invalidate_dcache_range(unsigned long start, unsigned long stop);
 void invalidate_dcache_all(void);
 void invalidate_icache_all(void);
+
+enum pgprot_attrs {
+	MMU_ATTR_RO,
+	MMU_ATTR_RX,
+	MMU_ATTR_RW,
+};
+
+/** pgprot_set_attrs() - Set page table permissions
+ *
+ * @addr: Physical address start
+ * @size: size of memory to change
+ * @perm: New permissions
+ *
+ * Return: 0 on success, error otherwise.
+ **/
+int pgprot_set_attrs(phys_addr_t addr, size_t size, u64 perm);
+
 /**
  * noncached_init() - Initialize non-cached memory region
  *