From 1c7d0c411c033f7158dccc34c795951b667dd591 Mon Sep 17 00:00:00 2001 From: Ilias Apalodimas Date: Thu, 20 Feb 2025 15:54:40 +0200 Subject: arm: Prepare linker scripts for memory permissions Upcoming patches are switching the memory mappings to RW, RO, RX after the U-Boot binary and its data are relocated. Add annotations in the linker scripts to and mark text, data, rodata sections and align them to a page boundary. It's worth noting that .efi_runtime memory permissions are left untouched for now. There's two problems with EFI currently. The first problem is that we bundle data, rodata and text in a single .efi_runtime section which also must be close to .text for now. As a result we also dont change the permissions for anything contained in CPUDIR/start.o. In order to fix that we have to decoule .text_rest, .text and .efi_runtime and have the runtime services on their own section with proper memory permission annotations (efi_rodata etc). The efi runtime regions (.efi_runtime_rel) can be relocated by the OS when the latter is calling SetVirtualAddressMap. Which means we have to configure those pages as RX for U-Boot but convert them to RWX just before ExitBootServices. It also needs extra code in efi_tuntime relocation code since R_AARCH64_NONE are emitted as well if we page align the section. Due to the above ignore EFI for now and fix it later once we have the rest in place. Acked-by: Jerome Forissier Tested-by: Neil Armstrong # on AML-S905X-CC Reviewed-by: Richard Henderson Signed-off-by: Ilias Apalodimas --- include/asm-generic/sections.h | 2 ++ 1 file changed, 2 insertions(+) (limited to 'include') diff --git a/include/asm-generic/sections.h b/include/asm-generic/sections.h index 3fd5c772a1a..024b1adde27 100644 --- a/include/asm-generic/sections.h +++ b/include/asm-generic/sections.h @@ -23,6 +23,7 @@ extern char __kprobes_text_start[], __kprobes_text_end[]; extern char __entry_text_start[], __entry_text_end[]; extern char __initdata_begin[], __initdata_end[]; extern char __start_rodata[], __end_rodata[]; +extern char __start_data[], __end_data[]; extern char __efi_helloworld_begin[]; extern char __efi_helloworld_end[]; extern char __efi_var_file_begin[]; @@ -63,6 +64,7 @@ static inline int arch_is_kernel_data(unsigned long addr) /* Start of U-Boot text region */ extern char __text_start[]; +extern char __text_end[]; /* This marks the text region which must be relocated */ extern char __image_copy_start[], __image_copy_end[]; -- cgit v1.3.1 From ec1c6cfb1cfce92909a248f10c36bd8b18894d7e Mon Sep 17 00:00:00 2001 From: Ilias Apalodimas Date: Thu, 20 Feb 2025 15:54:42 +0200 Subject: treewide: Add a function to change page permissions 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 # on AML-S905X-CC Signed-off-by: Ilias Apalodimas --- 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(+) (limited to 'include') diff --git a/arch/arc/lib/cache.c b/arch/arc/lib/cache.c index 5169fc627fa..08f9e7dceac 100644 --- a/arch/arc/lib/cache.c +++ b/arch/arc/lib/cache.c @@ -8,6 +8,7 @@ #include #include #include +#include #include #include #include @@ -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, enum pgprot_attrs perm) +{ + return -ENOSYS; +} diff --git a/arch/arm/cpu/arm926ejs/cache.c b/arch/arm/cpu/arm926ejs/cache.c index 5b87a3af91b..71b8ad0f71d 100644 --- a/arch/arm/cpu/arm926ejs/cache.c +++ b/arch/arm/cpu/arm926ejs/cache.c @@ -5,6 +5,7 @@ */ #include #include +#include #include #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, enum pgprot_attrs perm) +{ + return -ENOSYS; +} diff --git a/arch/arm/cpu/armv7/cache_v7.c b/arch/arm/cpu/armv7/cache_v7.c index d11420d2fdd..371dc92cd46 100644 --- a/arch/arm/cpu/armv7/cache_v7.c +++ b/arch/arm/cpu/armv7/cache_v7.c @@ -6,6 +6,7 @@ */ #include #include +#include #include #include #include @@ -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, enum pgprot_attrs perm) +{ + return -ENOSYS; +} diff --git a/arch/arm/cpu/armv7m/cache.c b/arch/arm/cpu/armv7m/cache.c index b6d08b7aad7..8e7db734055 100644 --- a/arch/arm/cpu/armv7m/cache.c +++ b/arch/arm/cpu/armv7m/cache.c @@ -11,6 +11,7 @@ #include #include #include +#include /* 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, enum pgprot_attrs perm) +{ + return -ENOSYS; +} diff --git a/arch/arm/cpu/armv8/cache_v8.c b/arch/arm/cpu/armv8/cache_v8.c index c9948e99e2e..12ae9bd0603 100644 --- a/arch/arm/cpu/armv8/cache_v8.c +++ b/arch/arm/cpu/armv8/cache_v8.c @@ -14,6 +14,7 @@ #include #include #include +#include DECLARE_GLOBAL_DATA_PTR; @@ -1032,6 +1033,30 @@ void mmu_change_region_attr(phys_addr_t addr, size_t siz, u64 attrs) mmu_change_region_attr_nobreak(addr, siz, attrs); } +int pgprot_set_attrs(phys_addr_t addr, size_t size, enum pgprot_attrs 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 %d\n", perm); + return -EINVAL; + } + + mmu_change_region_attr_nobreak(addr, size, attrs); + + return 0; +} + #else /* !CONFIG_IS_ENABLED(SYS_DCACHE_OFF) */ /* diff --git a/arch/arm/lib/cache.c b/arch/arm/lib/cache.c index 516754caeaf..dd19bd3e4fb 100644 --- a/arch/arm/lib/cache.c +++ b/arch/arm/lib/cache.c @@ -10,6 +10,7 @@ #include #include #include +#include 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, enum pgprot_attrs perm) +{ + return -ENOSYS; +} diff --git a/arch/m68k/lib/cache.c b/arch/m68k/lib/cache.c index 370ad40f142..a21fe327944 100644 --- a/arch/m68k/lib/cache.c +++ b/arch/m68k/lib/cache.c @@ -8,6 +8,7 @@ #include #include #include +#include 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, enum pgprot_attrs perm) +{ + return -ENOSYS; +} diff --git a/arch/nios2/lib/cache.c b/arch/nios2/lib/cache.c index 8f543f2a2f2..d7fd9ca8bd4 100644 --- a/arch/nios2/lib/cache.c +++ b/arch/nios2/lib/cache.c @@ -8,6 +8,7 @@ #include #include #include +#include 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, enum pgprot_attrs perm) +{ + return -ENOSYS; +} diff --git a/arch/powerpc/lib/cache.c b/arch/powerpc/lib/cache.c index a9cd7b8d30a..e4d9546039d 100644 --- a/arch/powerpc/lib/cache.c +++ b/arch/powerpc/lib/cache.c @@ -8,6 +8,7 @@ #include #include #include +#include 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, enum pgprot_attrs perm) +{ + return -ENOSYS; +} diff --git a/arch/riscv/lib/cache.c b/arch/riscv/lib/cache.c index 71e4937ab54..31aa30bc7d7 100644 --- a/arch/riscv/lib/cache.c +++ b/arch/riscv/lib/cache.c @@ -8,6 +8,7 @@ #include #include #include +#include #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, enum pgprot_attrs perm) +{ + return -ENOSYS; +} diff --git a/arch/sh/cpu/sh4/cache.c b/arch/sh/cpu/sh4/cache.c index 99acc599965..56161ee72e4 100644 --- a/arch/sh/cpu/sh4/cache.c +++ b/arch/sh/cpu/sh4/cache.c @@ -11,6 +11,7 @@ #include #include #include +#include #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, enum pgprot_attrs perm) +{ + return -ENOSYS; +} diff --git a/arch/xtensa/lib/cache.c b/arch/xtensa/lib/cache.c index e6a7f6827fc..1229b407783 100644 --- a/arch/xtensa/lib/cache.c +++ b/arch/xtensa/lib/cache.c @@ -6,6 +6,7 @@ #include #include +#include /* * 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, enum pgprot_attrs perm) +{ + return -ENOSYS; +} diff --git a/include/cpu_func.h b/include/cpu_func.h index 7e81c4364a7..70a41ead3f7 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, enum pgprot_attrs perm); + /** * noncached_init() - Initialize non-cached memory region * -- cgit v1.3.1