diff options
Diffstat (limited to 'arch/arm/kernel')
-rw-r--r-- | arch/arm/kernel/Makefile | 2 | ||||
-rw-r--r-- | arch/arm/kernel/armksyms.c | 183 | ||||
-rw-r--r-- | arch/arm/kernel/cpuidle.c | 2 | ||||
-rw-r--r-- | arch/arm/kernel/entry-ftrace.S | 3 | ||||
-rw-r--r-- | arch/arm/kernel/head-nommu.S | 16 | ||||
-rw-r--r-- | arch/arm/kernel/head.S | 3 | ||||
-rw-r--r-- | arch/arm/kernel/module-plts.c | 243 | ||||
-rw-r--r-- | arch/arm/kernel/module.lds | 3 | ||||
-rw-r--r-- | arch/arm/kernel/process.c | 3 | ||||
-rw-r--r-- | arch/arm/kernel/setup.c | 26 | ||||
-rw-r--r-- | arch/arm/kernel/smccc-call.S | 3 | ||||
-rw-r--r-- | arch/arm/kernel/smp.c | 15 | ||||
-rw-r--r-- | arch/arm/kernel/vdso.c | 11 | ||||
-rw-r--r-- | arch/arm/kernel/vmlinux-xip.lds.S | 1 | ||||
-rw-r--r-- | arch/arm/kernel/vmlinux.lds.S | 1 |
15 files changed, 195 insertions, 320 deletions
diff --git a/arch/arm/kernel/Makefile b/arch/arm/kernel/Makefile index ad325a8c7e1e..68c2c097cffe 100644 --- a/arch/arm/kernel/Makefile +++ b/arch/arm/kernel/Makefile @@ -33,7 +33,7 @@ endif obj-$(CONFIG_CPU_IDLE) += cpuidle.o obj-$(CONFIG_ISA_DMA_API) += dma.o obj-$(CONFIG_FIQ) += fiq.o fiqasm.o -obj-$(CONFIG_MODULES) += armksyms.o module.o +obj-$(CONFIG_MODULES) += module.o obj-$(CONFIG_ARM_MODULE_PLTS) += module-plts.o obj-$(CONFIG_ISA_DMA) += dma-isa.o obj-$(CONFIG_PCI) += bios32.o isa.o diff --git a/arch/arm/kernel/armksyms.c b/arch/arm/kernel/armksyms.c deleted file mode 100644 index 7e45f69a0ddc..000000000000 --- a/arch/arm/kernel/armksyms.c +++ /dev/null @@ -1,183 +0,0 @@ -/* - * linux/arch/arm/kernel/armksyms.c - * - * Copyright (C) 2000 Russell King - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ -#include <linux/export.h> -#include <linux/sched.h> -#include <linux/string.h> -#include <linux/cryptohash.h> -#include <linux/delay.h> -#include <linux/in6.h> -#include <linux/syscalls.h> -#include <linux/uaccess.h> -#include <linux/io.h> -#include <linux/arm-smccc.h> - -#include <asm/checksum.h> -#include <asm/ftrace.h> - -/* - * libgcc functions - functions that are used internally by the - * compiler... (prototypes are not correct though, but that - * doesn't really matter since they're not versioned). - */ -extern void __ashldi3(void); -extern void __ashrdi3(void); -extern void __divsi3(void); -extern void __lshrdi3(void); -extern void __modsi3(void); -extern void __muldi3(void); -extern void __ucmpdi2(void); -extern void __udivsi3(void); -extern void __umodsi3(void); -extern void __do_div64(void); -extern void __bswapsi2(void); -extern void __bswapdi2(void); - -extern void __aeabi_idiv(void); -extern void __aeabi_idivmod(void); -extern void __aeabi_lasr(void); -extern void __aeabi_llsl(void); -extern void __aeabi_llsr(void); -extern void __aeabi_lmul(void); -extern void __aeabi_uidiv(void); -extern void __aeabi_uidivmod(void); -extern void __aeabi_ulcmp(void); - -extern void fpundefinstr(void); - -void mmioset(void *, unsigned int, size_t); -void mmiocpy(void *, const void *, size_t); - - /* platform dependent support */ -EXPORT_SYMBOL(arm_delay_ops); - - /* networking */ -EXPORT_SYMBOL(csum_partial); -EXPORT_SYMBOL(csum_partial_copy_from_user); -EXPORT_SYMBOL(csum_partial_copy_nocheck); -EXPORT_SYMBOL(__csum_ipv6_magic); - - /* io */ -#ifndef __raw_readsb -EXPORT_SYMBOL(__raw_readsb); -#endif -#ifndef __raw_readsw -EXPORT_SYMBOL(__raw_readsw); -#endif -#ifndef __raw_readsl -EXPORT_SYMBOL(__raw_readsl); -#endif -#ifndef __raw_writesb -EXPORT_SYMBOL(__raw_writesb); -#endif -#ifndef __raw_writesw -EXPORT_SYMBOL(__raw_writesw); -#endif -#ifndef __raw_writesl -EXPORT_SYMBOL(__raw_writesl); -#endif - - /* string / mem functions */ -EXPORT_SYMBOL(strchr); -EXPORT_SYMBOL(strrchr); -EXPORT_SYMBOL(memset); -EXPORT_SYMBOL(memcpy); -EXPORT_SYMBOL(memmove); -EXPORT_SYMBOL(memchr); -EXPORT_SYMBOL(__memzero); - -EXPORT_SYMBOL(mmioset); -EXPORT_SYMBOL(mmiocpy); - -#ifdef CONFIG_MMU -EXPORT_SYMBOL(copy_page); - -EXPORT_SYMBOL(arm_copy_from_user); -EXPORT_SYMBOL(arm_copy_to_user); -EXPORT_SYMBOL(arm_clear_user); - -EXPORT_SYMBOL(__get_user_1); -EXPORT_SYMBOL(__get_user_2); -EXPORT_SYMBOL(__get_user_4); -EXPORT_SYMBOL(__get_user_8); - -#ifdef __ARMEB__ -EXPORT_SYMBOL(__get_user_64t_1); -EXPORT_SYMBOL(__get_user_64t_2); -EXPORT_SYMBOL(__get_user_64t_4); -EXPORT_SYMBOL(__get_user_32t_8); -#endif - -EXPORT_SYMBOL(__put_user_1); -EXPORT_SYMBOL(__put_user_2); -EXPORT_SYMBOL(__put_user_4); -EXPORT_SYMBOL(__put_user_8); -#endif - - /* gcc lib functions */ -EXPORT_SYMBOL(__ashldi3); -EXPORT_SYMBOL(__ashrdi3); -EXPORT_SYMBOL(__divsi3); -EXPORT_SYMBOL(__lshrdi3); -EXPORT_SYMBOL(__modsi3); -EXPORT_SYMBOL(__muldi3); -EXPORT_SYMBOL(__ucmpdi2); -EXPORT_SYMBOL(__udivsi3); -EXPORT_SYMBOL(__umodsi3); -EXPORT_SYMBOL(__do_div64); -EXPORT_SYMBOL(__bswapsi2); -EXPORT_SYMBOL(__bswapdi2); - -#ifdef CONFIG_AEABI -EXPORT_SYMBOL(__aeabi_idiv); -EXPORT_SYMBOL(__aeabi_idivmod); -EXPORT_SYMBOL(__aeabi_lasr); -EXPORT_SYMBOL(__aeabi_llsl); -EXPORT_SYMBOL(__aeabi_llsr); -EXPORT_SYMBOL(__aeabi_lmul); -EXPORT_SYMBOL(__aeabi_uidiv); -EXPORT_SYMBOL(__aeabi_uidivmod); -EXPORT_SYMBOL(__aeabi_ulcmp); -#endif - - /* bitops */ -EXPORT_SYMBOL(_set_bit); -EXPORT_SYMBOL(_test_and_set_bit); -EXPORT_SYMBOL(_clear_bit); -EXPORT_SYMBOL(_test_and_clear_bit); -EXPORT_SYMBOL(_change_bit); -EXPORT_SYMBOL(_test_and_change_bit); -EXPORT_SYMBOL(_find_first_zero_bit_le); -EXPORT_SYMBOL(_find_next_zero_bit_le); -EXPORT_SYMBOL(_find_first_bit_le); -EXPORT_SYMBOL(_find_next_bit_le); - -#ifdef __ARMEB__ -EXPORT_SYMBOL(_find_first_zero_bit_be); -EXPORT_SYMBOL(_find_next_zero_bit_be); -EXPORT_SYMBOL(_find_first_bit_be); -EXPORT_SYMBOL(_find_next_bit_be); -#endif - -#ifdef CONFIG_FUNCTION_TRACER -#ifdef CONFIG_OLD_MCOUNT -EXPORT_SYMBOL(mcount); -#endif -EXPORT_SYMBOL(__gnu_mcount_nc); -#endif - -#ifdef CONFIG_ARM_PATCH_PHYS_VIRT -EXPORT_SYMBOL(__pv_phys_pfn_offset); -EXPORT_SYMBOL(__pv_offset); -#endif - -#ifdef CONFIG_HAVE_ARM_SMCCC -EXPORT_SYMBOL(arm_smccc_smc); -EXPORT_SYMBOL(arm_smccc_hvc); -#endif diff --git a/arch/arm/kernel/cpuidle.c b/arch/arm/kernel/cpuidle.c index 7dccc964d75f..a3308ad1a024 100644 --- a/arch/arm/kernel/cpuidle.c +++ b/arch/arm/kernel/cpuidle.c @@ -19,7 +19,7 @@ extern struct of_cpuidle_method __cpuidle_method_of_table[]; static const struct of_cpuidle_method __cpuidle_method_of_table_sentinel __used __section(__cpuidle_method_of_table_end); -static struct cpuidle_ops cpuidle_ops[NR_CPUS]; +static struct cpuidle_ops cpuidle_ops[NR_CPUS] __ro_after_init; /** * arm_cpuidle_simple_enter() - a wrapper to cpu_do_idle() diff --git a/arch/arm/kernel/entry-ftrace.S b/arch/arm/kernel/entry-ftrace.S index c73c4030ca5d..b629d3f11c3d 100644 --- a/arch/arm/kernel/entry-ftrace.S +++ b/arch/arm/kernel/entry-ftrace.S @@ -7,6 +7,7 @@ #include <asm/assembler.h> #include <asm/ftrace.h> #include <asm/unwind.h> +#include <asm/export.h> #include "entry-header.S" @@ -153,6 +154,7 @@ ENTRY(mcount) __mcount _old #endif ENDPROC(mcount) +EXPORT_SYMBOL(mcount) #ifdef CONFIG_DYNAMIC_FTRACE ENTRY(ftrace_caller_old) @@ -205,6 +207,7 @@ UNWIND(.fnstart) #endif UNWIND(.fnend) ENDPROC(__gnu_mcount_nc) +EXPORT_SYMBOL(__gnu_mcount_nc) #ifdef CONFIG_DYNAMIC_FTRACE ENTRY(ftrace_caller) diff --git a/arch/arm/kernel/head-nommu.S b/arch/arm/kernel/head-nommu.S index fb1a69eb49c1..6b4eb27b8758 100644 --- a/arch/arm/kernel/head-nommu.S +++ b/arch/arm/kernel/head-nommu.S @@ -158,7 +158,21 @@ __after_proc_init: bic r0, r0, #CR_V #endif mcr p15, 0, r0, c1, c0, 0 @ write control reg -#endif /* CONFIG_CPU_CP15 */ +#elif defined (CONFIG_CPU_V7M) + /* For V7M systems we want to modify the CCR similarly to the SCTLR */ +#ifdef CONFIG_CPU_DCACHE_DISABLE + bic r0, r0, #V7M_SCB_CCR_DC +#endif +#ifdef CONFIG_CPU_BPREDICT_DISABLE + bic r0, r0, #V7M_SCB_CCR_BP +#endif +#ifdef CONFIG_CPU_ICACHE_DISABLE + bic r0, r0, #V7M_SCB_CCR_IC +#endif + movw r3, #:lower16:(BASEADDR_V7M_SCB + V7M_SCB_CCR) + movt r3, #:upper16:(BASEADDR_V7M_SCB + V7M_SCB_CCR) + str r0, [r3] +#endif /* CONFIG_CPU_CP15 elif CONFIG_CPU_V7M */ ret lr ENDPROC(__after_proc_init) .ltorg diff --git a/arch/arm/kernel/head.S b/arch/arm/kernel/head.S index 04286fd9e09c..f41cee4c5746 100644 --- a/arch/arm/kernel/head.S +++ b/arch/arm/kernel/head.S @@ -22,6 +22,7 @@ #include <asm/memory.h> #include <asm/thread_info.h> #include <asm/pgtable.h> +#include <asm/export.h> #if defined(CONFIG_DEBUG_LL) && !defined(CONFIG_DEBUG_SEMIHOSTING) #include CONFIG_DEBUG_LL_INCLUDE @@ -727,6 +728,8 @@ __pv_phys_pfn_offset: __pv_offset: .quad 0 .size __pv_offset, . -__pv_offset +EXPORT_SYMBOL(__pv_phys_pfn_offset) +EXPORT_SYMBOL(__pv_offset) #endif #include "head-common.S" diff --git a/arch/arm/kernel/module-plts.c b/arch/arm/kernel/module-plts.c index 0c7efc3446c0..3a5cba90c971 100644 --- a/arch/arm/kernel/module-plts.c +++ b/arch/arm/kernel/module-plts.c @@ -9,6 +9,7 @@ #include <linux/elf.h> #include <linux/kernel.h> #include <linux/module.h> +#include <linux/sort.h> #include <asm/cache.h> #include <asm/opcodes.h> @@ -30,154 +31,198 @@ struct plt_entries { u32 lit[PLT_ENT_COUNT]; }; -static bool in_init(const struct module *mod, u32 addr) +u32 get_module_plt(struct module *mod, unsigned long loc, Elf32_Addr val) { - return addr - (u32)mod->init_layout.base < mod->init_layout.size; + struct plt_entries *plt = (struct plt_entries *)mod->arch.plt->sh_addr; + int idx = 0; + + /* + * Look for an existing entry pointing to 'val'. Given that the + * relocations are sorted, this will be the last entry we allocated. + * (if one exists). + */ + if (mod->arch.plt_count > 0) { + plt += (mod->arch.plt_count - 1) / PLT_ENT_COUNT; + idx = (mod->arch.plt_count - 1) % PLT_ENT_COUNT; + + if (plt->lit[idx] == val) + return (u32)&plt->ldr[idx]; + + idx = (idx + 1) % PLT_ENT_COUNT; + if (!idx) + plt++; + } + + mod->arch.plt_count++; + BUG_ON(mod->arch.plt_count * PLT_ENT_SIZE > mod->arch.plt->sh_size); + + if (!idx) + /* Populate a new set of entries */ + *plt = (struct plt_entries){ + { [0 ... PLT_ENT_COUNT - 1] = PLT_ENT_LDR, }, + { val, } + }; + else + plt->lit[idx] = val; + + return (u32)&plt->ldr[idx]; } -u32 get_module_plt(struct module *mod, unsigned long loc, Elf32_Addr val) +#define cmp_3way(a,b) ((a) < (b) ? -1 : (a) > (b)) + +static int cmp_rel(const void *a, const void *b) { - struct plt_entries *plt, *plt_end; - int c, *count; - - if (in_init(mod, loc)) { - plt = (void *)mod->arch.init_plt->sh_addr; - plt_end = (void *)plt + mod->arch.init_plt->sh_size; - count = &mod->arch.init_plt_count; - } else { - plt = (void *)mod->arch.core_plt->sh_addr; - plt_end = (void *)plt + mod->arch.core_plt->sh_size; - count = &mod->arch.core_plt_count; - } + const Elf32_Rel *x = a, *y = b; + int i; - /* Look for an existing entry pointing to 'val' */ - for (c = *count; plt < plt_end; c -= PLT_ENT_COUNT, plt++) { - int i; - - if (!c) { - /* Populate a new set of entries */ - *plt = (struct plt_entries){ - { [0 ... PLT_ENT_COUNT - 1] = PLT_ENT_LDR, }, - { val, } - }; - ++*count; - return (u32)plt->ldr; - } - for (i = 0; i < PLT_ENT_COUNT; i++) { - if (!plt->lit[i]) { - plt->lit[i] = val; - ++*count; - } - if (plt->lit[i] == val) - return (u32)&plt->ldr[i]; - } + /* sort by type and symbol index */ + i = cmp_3way(ELF32_R_TYPE(x->r_info), ELF32_R_TYPE(y->r_info)); + if (i == 0) + i = cmp_3way(ELF32_R_SYM(x->r_info), ELF32_R_SYM(y->r_info)); + return i; +} + +static bool is_zero_addend_relocation(Elf32_Addr base, const Elf32_Rel *rel) +{ + u32 *tval = (u32 *)(base + rel->r_offset); + + /* + * Do a bitwise compare on the raw addend rather than fully decoding + * the offset and doing an arithmetic comparison. + * Note that a zero-addend jump/call relocation is encoded taking the + * PC bias into account, i.e., -8 for ARM and -4 for Thumb2. + */ + switch (ELF32_R_TYPE(rel->r_info)) { + u16 upper, lower; + + case R_ARM_THM_CALL: + case R_ARM_THM_JUMP24: + upper = __mem_to_opcode_thumb16(((u16 *)tval)[0]); + lower = __mem_to_opcode_thumb16(((u16 *)tval)[1]); + + return (upper & 0x7ff) == 0x7ff && (lower & 0x2fff) == 0x2ffe; + + case R_ARM_CALL: + case R_ARM_PC24: + case R_ARM_JUMP24: + return (__mem_to_opcode_arm(*tval) & 0xffffff) == 0xfffffe; } BUG(); } -static int duplicate_rel(Elf32_Addr base, const Elf32_Rel *rel, int num, - u32 mask) +static bool duplicate_rel(Elf32_Addr base, const Elf32_Rel *rel, int num) { - u32 *loc1, *loc2; - int i; + const Elf32_Rel *prev; - for (i = 0; i < num; i++) { - if (rel[i].r_info != rel[num].r_info) - continue; + /* + * Entries are sorted by type and symbol index. That means that, + * if a duplicate entry exists, it must be in the preceding + * slot. + */ + if (!num) + return false; - /* - * Identical relocation types against identical symbols can - * still result in different PLT entries if the addend in the - * place is different. So resolve the target of the relocation - * to compare the values. - */ - loc1 = (u32 *)(base + rel[i].r_offset); - loc2 = (u32 *)(base + rel[num].r_offset); - if (((*loc1 ^ *loc2) & mask) == 0) - return 1; - } - return 0; + prev = rel + num - 1; + return cmp_rel(rel + num, prev) == 0 && + is_zero_addend_relocation(base, prev); } /* Count how many PLT entries we may need */ -static unsigned int count_plts(Elf32_Addr base, const Elf32_Rel *rel, int num) +static unsigned int count_plts(const Elf32_Sym *syms, Elf32_Addr base, + const Elf32_Rel *rel, int num) { unsigned int ret = 0; + const Elf32_Sym *s; int i; - /* - * Sure, this is order(n^2), but it's usually short, and not - * time critical - */ - for (i = 0; i < num; i++) + for (i = 0; i < num; i++) { switch (ELF32_R_TYPE(rel[i].r_info)) { case R_ARM_CALL: case R_ARM_PC24: case R_ARM_JUMP24: - if (!duplicate_rel(base, rel, i, - __opcode_to_mem_arm(0x00ffffff))) - ret++; - break; -#ifdef CONFIG_THUMB2_KERNEL case R_ARM_THM_CALL: case R_ARM_THM_JUMP24: - if (!duplicate_rel(base, rel, i, - __opcode_to_mem_thumb32(0x07ff2fff))) + /* + * We only have to consider branch targets that resolve + * to undefined symbols. This is not simply a heuristic, + * it is a fundamental limitation, since the PLT itself + * is part of the module, and needs to be within range + * as well, so modules can never grow beyond that limit. + */ + s = syms + ELF32_R_SYM(rel[i].r_info); + if (s->st_shndx != SHN_UNDEF) + break; + + /* + * Jump relocations with non-zero addends against + * undefined symbols are supported by the ELF spec, but + * do not occur in practice (e.g., 'jump n bytes past + * the entry point of undefined function symbol f'). + * So we need to support them, but there is no need to + * take them into consideration when trying to optimize + * this code. So let's only check for duplicates when + * the addend is zero. + */ + if (!is_zero_addend_relocation(base, rel + i) || + !duplicate_rel(base, rel, i)) ret++; -#endif } + } return ret; } int module_frob_arch_sections(Elf_Ehdr *ehdr, Elf_Shdr *sechdrs, char *secstrings, struct module *mod) { - unsigned long core_plts = 0, init_plts = 0; + unsigned long plts = 0; Elf32_Shdr *s, *sechdrs_end = sechdrs + ehdr->e_shnum; + Elf32_Sym *syms = NULL; /* * To store the PLTs, we expand the .text section for core module code - * and the .init.text section for initialization code. + * and for initialization code. */ - for (s = sechdrs; s < sechdrs_end; ++s) - if (strcmp(".core.plt", secstrings + s->sh_name) == 0) - mod->arch.core_plt = s; - else if (strcmp(".init.plt", secstrings + s->sh_name) == 0) - mod->arch.init_plt = s; - - if (!mod->arch.core_plt || !mod->arch.init_plt) { - pr_err("%s: sections missing\n", mod->name); + for (s = sechdrs; s < sechdrs_end; ++s) { + if (strcmp(".plt", secstrings + s->sh_name) == 0) + mod->arch.plt = s; + else if (s->sh_type == SHT_SYMTAB) + syms = (Elf32_Sym *)s->sh_addr; + } + + if (!mod->arch.plt) { + pr_err("%s: module PLT section missing\n", mod->name); + return -ENOEXEC; + } + if (!syms) { + pr_err("%s: module symtab section missing\n", mod->name); return -ENOEXEC; } for (s = sechdrs + 1; s < sechdrs_end; ++s) { - const Elf32_Rel *rels = (void *)ehdr + s->sh_offset; + Elf32_Rel *rels = (void *)ehdr + s->sh_offset; int numrels = s->sh_size / sizeof(Elf32_Rel); Elf32_Shdr *dstsec = sechdrs + s->sh_info; if (s->sh_type != SHT_REL) continue; - if (strstr(secstrings + s->sh_name, ".init")) - init_plts += count_plts(dstsec->sh_addr, rels, numrels); - else - core_plts += count_plts(dstsec->sh_addr, rels, numrels); + /* ignore relocations that operate on non-exec sections */ + if (!(dstsec->sh_flags & SHF_EXECINSTR)) + continue; + + /* sort by type and symbol index */ + sort(rels, numrels, sizeof(Elf32_Rel), cmp_rel, NULL); + + plts += count_plts(syms, dstsec->sh_addr, rels, numrels); } - mod->arch.core_plt->sh_type = SHT_NOBITS; - mod->arch.core_plt->sh_flags = SHF_EXECINSTR | SHF_ALLOC; - mod->arch.core_plt->sh_addralign = L1_CACHE_BYTES; - mod->arch.core_plt->sh_size = round_up(core_plts * PLT_ENT_SIZE, - sizeof(struct plt_entries)); - mod->arch.core_plt_count = 0; - - mod->arch.init_plt->sh_type = SHT_NOBITS; - mod->arch.init_plt->sh_flags = SHF_EXECINSTR | SHF_ALLOC; - mod->arch.init_plt->sh_addralign = L1_CACHE_BYTES; - mod->arch.init_plt->sh_size = round_up(init_plts * PLT_ENT_SIZE, - sizeof(struct plt_entries)); - mod->arch.init_plt_count = 0; - pr_debug("%s: core.plt=%x, init.plt=%x\n", __func__, - mod->arch.core_plt->sh_size, mod->arch.init_plt->sh_size); + mod->arch.plt->sh_type = SHT_NOBITS; + mod->arch.plt->sh_flags = SHF_EXECINSTR | SHF_ALLOC; + mod->arch.plt->sh_addralign = L1_CACHE_BYTES; + mod->arch.plt->sh_size = round_up(plts * PLT_ENT_SIZE, + sizeof(struct plt_entries)); + mod->arch.plt_count = 0; + + pr_debug("%s: plt=%x\n", __func__, mod->arch.plt->sh_size); return 0; } diff --git a/arch/arm/kernel/module.lds b/arch/arm/kernel/module.lds index 3682fa107918..05881e2b414c 100644 --- a/arch/arm/kernel/module.lds +++ b/arch/arm/kernel/module.lds @@ -1,4 +1,3 @@ SECTIONS { - .core.plt : { BYTE(0) } - .init.plt : { BYTE(0) } + .plt : { BYTE(0) } } diff --git a/arch/arm/kernel/process.c b/arch/arm/kernel/process.c index 612eb530f33f..91d2d5b01414 100644 --- a/arch/arm/kernel/process.c +++ b/arch/arm/kernel/process.c @@ -318,8 +318,7 @@ unsigned long get_wchan(struct task_struct *p) unsigned long arch_randomize_brk(struct mm_struct *mm) { - unsigned long range_end = mm->brk + 0x02000000; - return randomize_range(mm->brk, range_end, 0) ? : mm->brk; + return randomize_page(mm->brk, 0x02000000); } #ifdef CONFIG_MMU diff --git a/arch/arm/kernel/setup.c b/arch/arm/kernel/setup.c index df7f2a75e769..34e3f3c45634 100644 --- a/arch/arm/kernel/setup.c +++ b/arch/arm/kernel/setup.c @@ -114,19 +114,19 @@ EXPORT_SYMBOL(elf_hwcap2); #ifdef MULTI_CPU -struct processor processor __read_mostly; +struct processor processor __ro_after_init; #endif #ifdef MULTI_TLB -struct cpu_tlb_fns cpu_tlb __read_mostly; +struct cpu_tlb_fns cpu_tlb __ro_after_init; #endif #ifdef MULTI_USER -struct cpu_user_fns cpu_user __read_mostly; +struct cpu_user_fns cpu_user __ro_after_init; #endif #ifdef MULTI_CACHE -struct cpu_cache_fns cpu_cache __read_mostly; +struct cpu_cache_fns cpu_cache __ro_after_init; #endif #ifdef CONFIG_OUTER_CACHE -struct outer_cache_fns outer_cache __read_mostly; +struct outer_cache_fns outer_cache __ro_after_init; EXPORT_SYMBOL(outer_cache); #endif @@ -290,12 +290,9 @@ static int cpu_has_aliasing_icache(unsigned int arch) /* arch specifies the register format */ switch (arch) { case CPU_ARCH_ARMv7: - asm("mcr p15, 2, %0, c0, c0, 0 @ set CSSELR" - : /* No output operands */ - : "r" (1)); + set_csselr(CSSELR_ICACHE | CSSELR_L1); isb(); - asm("mrc p15, 1, %0, c0, c0, 0 @ read CCSIDR" - : "=r" (id_reg)); + id_reg = read_ccsidr(); line_size = 4 << ((id_reg & 0x7) + 2); num_sets = ((id_reg >> 13) & 0x7fff) + 1; aliasing_icache = (line_size * num_sets) > PAGE_SIZE; @@ -315,11 +312,12 @@ static void __init cacheid_init(void) { unsigned int arch = cpu_architecture(); - if (arch == CPU_ARCH_ARMv7M) { - cacheid = 0; - } else if (arch >= CPU_ARCH_ARMv6) { + if (arch >= CPU_ARCH_ARMv6) { unsigned int cachetype = read_cpuid_cachetype(); - if ((cachetype & (7 << 29)) == 4 << 29) { + + if ((arch == CPU_ARCH_ARMv7M) && !cachetype) { + cacheid = 0; + } else if ((cachetype & (7 << 29)) == 4 << 29) { /* ARMv7 register format */ arch = CPU_ARCH_ARMv7; cacheid = CACHEID_VIPT_NONALIASING; diff --git a/arch/arm/kernel/smccc-call.S b/arch/arm/kernel/smccc-call.S index 2e48b674aab1..37669e7e13af 100644 --- a/arch/arm/kernel/smccc-call.S +++ b/arch/arm/kernel/smccc-call.S @@ -16,6 +16,7 @@ #include <asm/opcodes-sec.h> #include <asm/opcodes-virt.h> #include <asm/unwind.h> +#include <asm/export.h> /* * Wrap c macros in asm macros to delay expansion until after the @@ -51,6 +52,7 @@ UNWIND( .fnend) ENTRY(arm_smccc_smc) SMCCC SMCCC_SMC ENDPROC(arm_smccc_smc) +EXPORT_SYMBOL(arm_smccc_smc) /* * void smccc_hvc(unsigned long a0, unsigned long a1, unsigned long a2, @@ -60,3 +62,4 @@ ENDPROC(arm_smccc_smc) ENTRY(arm_smccc_hvc) SMCCC SMCCC_HVC ENDPROC(arm_smccc_hvc) +EXPORT_SYMBOL(arm_smccc_hvc) diff --git a/arch/arm/kernel/smp.c b/arch/arm/kernel/smp.c index 861521606c6d..7dd14e8395e6 100644 --- a/arch/arm/kernel/smp.c +++ b/arch/arm/kernel/smp.c @@ -82,7 +82,7 @@ enum ipi_msg_type { static DECLARE_COMPLETION(cpu_running); -static struct smp_operations smp_ops; +static struct smp_operations smp_ops __ro_after_init; void __init smp_set_ops(const struct smp_operations *ops) { @@ -748,19 +748,10 @@ core_initcall(register_cpufreq_notifier); static void raise_nmi(cpumask_t *mask) { - /* - * Generate the backtrace directly if we are running in a calling - * context that is not preemptible by the backtrace IPI. Note - * that nmi_cpu_backtrace() automatically removes the current cpu - * from mask. - */ - if (cpumask_test_cpu(smp_processor_id(), mask) && irqs_disabled()) - nmi_cpu_backtrace(NULL); - smp_cross_call(mask, IPI_CPU_BACKTRACE); } -void arch_trigger_all_cpu_backtrace(bool include_self) +void arch_trigger_cpumask_backtrace(const cpumask_t *mask, bool exclude_self) { - nmi_trigger_all_cpu_backtrace(include_self, raise_nmi); + nmi_trigger_cpumask_backtrace(mask, exclude_self, raise_nmi); } diff --git a/arch/arm/kernel/vdso.c b/arch/arm/kernel/vdso.c index a0affd14086a..53cf86cf2d1a 100644 --- a/arch/arm/kernel/vdso.c +++ b/arch/arm/kernel/vdso.c @@ -17,6 +17,7 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ +#include <linux/cache.h> #include <linux/elf.h> #include <linux/err.h> #include <linux/kernel.h> @@ -39,7 +40,7 @@ static struct page **vdso_text_pagelist; /* Total number of pages needed for the data and text portions of the VDSO. */ -unsigned int vdso_total_pages __read_mostly; +unsigned int vdso_total_pages __ro_after_init; /* * The VDSO data page. @@ -47,13 +48,13 @@ unsigned int vdso_total_pages __read_mostly; static union vdso_data_store vdso_data_store __page_aligned_data; static struct vdso_data *vdso_data = &vdso_data_store.data; -static struct page *vdso_data_page; -static struct vm_special_mapping vdso_data_mapping = { +static struct page *vdso_data_page __ro_after_init; +static const struct vm_special_mapping vdso_data_mapping = { .name = "[vvar]", .pages = &vdso_data_page, }; -static struct vm_special_mapping vdso_text_mapping = { +static struct vm_special_mapping vdso_text_mapping __ro_after_init = { .name = "[vdso]", }; @@ -67,7 +68,7 @@ struct elfinfo { /* Cached result of boot-time check for whether the arch timer exists, * and if so, whether the virtual counter is useable. */ -static bool cntvct_ok __read_mostly; +static bool cntvct_ok __ro_after_init; static bool __init cntvct_functional(void) { diff --git a/arch/arm/kernel/vmlinux-xip.lds.S b/arch/arm/kernel/vmlinux-xip.lds.S index cba1ec899a69..7fa487ef7e2f 100644 --- a/arch/arm/kernel/vmlinux-xip.lds.S +++ b/arch/arm/kernel/vmlinux-xip.lds.S @@ -98,6 +98,7 @@ SECTIONS IRQENTRY_TEXT TEXT_TEXT SCHED_TEXT + CPUIDLE_TEXT LOCK_TEXT KPROBES_TEXT *(.gnu.warning) diff --git a/arch/arm/kernel/vmlinux.lds.S b/arch/arm/kernel/vmlinux.lds.S index d24e5dd2aa7a..f7f55df0bf7b 100644 --- a/arch/arm/kernel/vmlinux.lds.S +++ b/arch/arm/kernel/vmlinux.lds.S @@ -111,6 +111,7 @@ SECTIONS SOFTIRQENTRY_TEXT TEXT_TEXT SCHED_TEXT + CPUIDLE_TEXT LOCK_TEXT HYPERVISOR_TEXT KPROBES_TEXT |