diff options
Diffstat (limited to 'arch')
-rw-r--r-- | arch/arc/lib/cache.c | 6 | ||||
-rw-r--r-- | arch/arm/cpu/arm926ejs/cache.c | 6 | ||||
-rw-r--r-- | arch/arm/cpu/armv7/cache_v7.c | 6 | ||||
-rw-r--r-- | arch/arm/cpu/armv7m/cache.c | 6 | ||||
-rw-r--r-- | arch/arm/cpu/armv8/cache_v8.c | 99 | ||||
-rw-r--r-- | arch/arm/cpu/armv8/u-boot.lds | 59 | ||||
-rw-r--r-- | arch/arm/include/asm/armv8/mmu.h | 2 | ||||
-rw-r--r-- | arch/arm/include/asm/system.h | 18 | ||||
-rw-r--r-- | arch/arm/lib/cache.c | 6 | ||||
-rw-r--r-- | arch/m68k/lib/cache.c | 6 | ||||
-rw-r--r-- | arch/nios2/lib/cache.c | 6 | ||||
-rw-r--r-- | arch/powerpc/lib/cache.c | 6 | ||||
-rw-r--r-- | arch/riscv/lib/cache.c | 6 | ||||
-rw-r--r-- | arch/sh/cpu/sh4/cache.c | 6 | ||||
-rw-r--r-- | arch/xtensa/lib/cache.c | 6 |
15 files changed, 202 insertions, 42 deletions
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 <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, 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 <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, 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 <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, 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 <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, 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 5d6953ffedd..12ae9bd0603 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; @@ -421,7 +422,7 @@ static int count_ranges(void) return count; } -#define ALL_ATTRS (3 << 8 | PMD_ATTRINDX_MASK) +#define ALL_ATTRS (3 << 8 | PMD_ATTRMASK) #define PTE_IS_TABLE(pte, level) (pte_type(&(pte)) == PTE_TYPE_TABLE && (level) < 3) enum walker_state { @@ -568,6 +569,20 @@ static void pretty_print_table_attrs(u64 pte) static void pretty_print_block_attrs(u64 pte) { u64 attrs = pte & PMD_ATTRINDX_MASK; + u64 perm_attrs = pte & PMD_ATTRMASK; + char mem_attrs[16] = { 0 }; + int cnt = 0; + + if (perm_attrs & PTE_BLOCK_PXN) + cnt += snprintf(mem_attrs + cnt, sizeof(mem_attrs) - cnt, "PXN "); + if (perm_attrs & PTE_BLOCK_UXN) + cnt += snprintf(mem_attrs + cnt, sizeof(mem_attrs) - cnt, "UXN "); + if (perm_attrs & PTE_BLOCK_RO) + cnt += snprintf(mem_attrs + cnt, sizeof(mem_attrs) - cnt, "RO"); + if (!mem_attrs[0]) + snprintf(mem_attrs, sizeof(mem_attrs), "RWX "); + + printf(" | %-10s", mem_attrs); switch (attrs) { case PTE_BLOCK_MEMTYPE(MT_DEVICE_NGNRNE): @@ -613,6 +628,7 @@ static void print_pte(u64 pte, int level) { if (PTE_IS_TABLE(pte, level)) { printf(" %-5s", "Table"); + printf(" %-12s", "|"); pretty_print_table_attrs(pte); } else { pretty_print_pte_type(pte); @@ -642,9 +658,9 @@ static bool pagetable_print_entry(u64 start_attrs, u64 end, int va_bits, int lev printf("%*s", indent * 2, ""); if (PTE_IS_TABLE(start_attrs, level)) - printf("[%#011llx]%14s", _addr, ""); + printf("[%#016llx]%19s", _addr, ""); else - printf("[%#011llx - %#011llx]", _addr, end); + printf("[%#016llx - %#016llx]", _addr, end); printf("%*s | ", (3 - level) * 2, ""); print_pte(start_attrs, level); @@ -952,61 +968,93 @@ void mmu_set_region_dcache_behaviour(phys_addr_t start, size_t size, flush_dcache_range(real_start, real_start + real_size); } -/* - * Modify MMU table for a region with updated PXN/UXN/Memory type/valid bits. - * The procecess is break-before-make. The target region will be marked as - * invalid during the process of changing. - */ -void mmu_change_region_attr(phys_addr_t addr, size_t siz, u64 attrs) +void mmu_change_region_attr_nobreak(phys_addr_t addr, size_t siz, u64 attrs) { int level; u64 r, size, start; - start = addr; - size = siz; /* * Loop through the address range until we find a page granule that fits - * our alignment constraints, then set it to "invalid". + * our alignment constraints and set the new permissions */ + start = addr; + size = siz; while (size > 0) { for (level = 1; level < 4; level++) { - /* Set PTE to fault */ - r = set_one_region(start, size, PTE_TYPE_FAULT, true, - level); + /* Set PTE to new attributes */ + r = set_one_region(start, size, attrs, true, level); if (r) { - /* PTE successfully invalidated */ + /* PTE successfully updated */ size -= r; start += r; break; } } } - flush_dcache_range(gd->arch.tlb_addr, gd->arch.tlb_addr + gd->arch.tlb_size); __asm_invalidate_tlb_all(); +} + +/* + * Modify MMU table for a region with updated PXN/UXN/Memory type/valid bits. + * The procecess is break-before-make. The target region will be marked as + * invalid during the process of changing. + */ +void mmu_change_region_attr(phys_addr_t addr, size_t siz, u64 attrs) +{ + int level; + u64 r, size, start; + start = addr; + size = siz; /* * Loop through the address range until we find a page granule that fits - * our alignment constraints, then set it to the new cache attributes + * our alignment constraints, then set it to "invalid". */ - start = addr; - size = siz; while (size > 0) { for (level = 1; level < 4; level++) { - /* Set PTE to new attributes */ - r = set_one_region(start, size, attrs, true, level); + /* Set PTE to fault */ + r = set_one_region(start, size, PTE_TYPE_FAULT, true, + level); if (r) { - /* PTE successfully updated */ + /* PTE successfully invalidated */ size -= r; start += r; break; } } } + flush_dcache_range(gd->arch.tlb_addr, gd->arch.tlb_addr + gd->arch.tlb_size); __asm_invalidate_tlb_all(); + + 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) */ @@ -1112,3 +1160,8 @@ void __weak enable_caches(void) icache_enable(); dcache_enable(); } + +void arch_dump_mem_attrs(void) +{ + dump_pagetable(gd->arch.tlb_addr, get_tcr(NULL, NULL)); +} diff --git a/arch/arm/cpu/armv8/u-boot.lds b/arch/arm/cpu/armv8/u-boot.lds index 857f44412e0..f4ce98c82c8 100644 --- a/arch/arm/cpu/armv8/u-boot.lds +++ b/arch/arm/cpu/armv8/u-boot.lds @@ -36,9 +36,18 @@ SECTIONS __efi_runtime_stop = .; } +#ifdef CONFIG_MMU_PGPROT + .text_rest ALIGN(CONSTANT(COMMONPAGESIZE)) : +#else .text_rest : +#endif { + __text_start = .; *(.text*) +#ifdef CONFIG_MMU_PGPROT + . = ALIGN(CONSTANT(COMMONPAGESIZE)); +#endif + __text_end = .; } #ifdef CONFIG_ARMV8_PSCI @@ -97,35 +106,43 @@ SECTIONS LONG(0x1d1071c); /* Must output something to reset LMA */ } #endif - - . = ALIGN(8); - .rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) } - - . = ALIGN(8); - .data : { - *(.data*) + .efi_runtime_rel : { + __efi_runtime_rel_start = .; + *(.rel*.efi_runtime) + *(.rel*.efi_runtime.*) + __efi_runtime_rel_stop = .; } - . = ALIGN(8); - - . = .; +#ifdef CONFIG_MMU_PGPROT + .rodata ALIGN(CONSTANT(COMMONPAGESIZE)): { +#else + .rodata ALIGN(8) : { +#endif + __start_rodata = .; + *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) + } - . = ALIGN(8); - __u_boot_list : { + __u_boot_list ALIGN(8) : { KEEP(*(SORT(__u_boot_list*))); +#ifdef CONFIG_MMU_PGPROT + . = ALIGN(CONSTANT(COMMONPAGESIZE)); +#endif + __end_rodata = .; } - .efi_runtime_rel : { - __efi_runtime_rel_start = .; - *(.rel*.efi_runtime) - *(.rel*.efi_runtime.*) - __efi_runtime_rel_stop = .; +#ifdef CONFIG_MMU_PGPROT + .data ALIGN(CONSTANT(COMMONPAGESIZE)) : { +#else + .data ALIGN(8) : { +#endif + __start_data = .; + *(.data*) } . = ALIGN(8); __image_copy_end = .; - .rela.dyn : { + .rela.dyn ALIGN(8) : { __rel_dyn_start = .; *(.rela*) __rel_dyn_end = .; @@ -136,11 +153,15 @@ SECTIONS /* * arch/arm/lib/crt0_64.S assumes __bss_start - __bss_end % 8 == 0 */ - .bss ALIGN(8) : { + .bss ADDR(.rela.dyn) (OVERLAY) : { __bss_start = .; *(.bss*) . = ALIGN(8); __bss_end = .; +#ifdef CONFIG_MMU_PGPROT + . = ALIGN(CONSTANT(COMMONPAGESIZE)); +#endif + __end_data = .; } /DISCARD/ : { *(.dynsym) } diff --git a/arch/arm/include/asm/armv8/mmu.h b/arch/arm/include/asm/armv8/mmu.h index 0ab681c893d..6af8cd111a4 100644 --- a/arch/arm/include/asm/armv8/mmu.h +++ b/arch/arm/include/asm/armv8/mmu.h @@ -66,6 +66,7 @@ #define PTE_BLOCK_NG (1 << 11) #define PTE_BLOCK_PXN (UL(1) << 53) #define PTE_BLOCK_UXN (UL(1) << 54) +#define PTE_BLOCK_RO (UL(1) << 7) /* * AttrIndx[2:0] @@ -75,6 +76,7 @@ #define PMD_ATTRMASK (PTE_BLOCK_PXN | \ PTE_BLOCK_UXN | \ PMD_ATTRINDX_MASK | \ + PTE_BLOCK_RO | \ PTE_TYPE_VALID) /* diff --git a/arch/arm/include/asm/system.h b/arch/arm/include/asm/system.h index 091082281c7..849b3d0efb7 100644 --- a/arch/arm/include/asm/system.h +++ b/arch/arm/include/asm/system.h @@ -303,8 +303,26 @@ void flush_l3_cache(void); * @emerg: Also map the region in the emergency table */ void mmu_map_region(phys_addr_t start, u64 size, bool emerg); + +/** + * mmu_change_region_attr() - change a mapped region attributes + * + * @start: Start address of the region + * @size: Size of the region + * @aatrs: New attributes + */ void mmu_change_region_attr(phys_addr_t start, size_t size, u64 attrs); +/** + * mmu_change_region_attr_nobreak() - change a mapped region attributes without doing + * break-before-make + * + * @start: Start address of the region + * @size: Size of the region + * @aatrs: New attributes + */ +void mmu_change_region_attr_nobreak(phys_addr_t addr, size_t size, u64 attrs); + /* * smc_call() - issue a secure monitor call * 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 <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, 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 <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, 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 <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, 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 <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, 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 <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, 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 <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, 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 <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, enum pgprot_attrs perm) +{ + return -ENOSYS; +} |