diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2022-12-14 02:22:14 +0300 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2022-12-14 02:22:14 +0300 |
commit | 4cb1fc6fffe4910845e183d1a2dfe9509ba1062c (patch) | |
tree | f7986abd08f7bc3f8e769a1da66cb00ad745f26e /arch/arm/kernel | |
parent | 740afa4d39414516c36836ad88bed8294c72ba5f (diff) | |
parent | aaa4dd1b47f5ff5ef477fec5dcc6c397b457f1c2 (diff) | |
download | linux-4cb1fc6fffe4910845e183d1a2dfe9509ba1062c.tar.xz |
Merge tag 'for-linus' of git://git.armlinux.org.uk/~rmk/linux-arm
Pull ARM updates from Russell King:
- update unwinder to cope with module PLTs
- enable UBSAN on ARM
- improve kernel fault message
- update UEFI runtime page tables dump
- avoid clang's __aeabi_uldivmod generated in NWFPE code
- disable FIQs on CPU shutdown paths
- update XOR register usage
- a number of build updates (using .arch, thread pointer, removal of
lazy evaluation in Makefile)
- conversion of stacktrace code to stackwalk
- findbit assembly updates
- hwcap feature updates for ARMv8 CPUs
- instruction dump updates for big-endian platforms
- support for function error injection
* tag 'for-linus' of git://git.armlinux.org.uk/~rmk/linux-arm: (31 commits)
ARM: 9279/1: support function error injection
ARM: 9277/1: Make the dumped instructions are consistent with the disassembled ones
ARM: 9276/1: Refactor dump_instr()
ARM: 9275/1: Drop '-mthumb' from AFLAGS_ISA
ARM: 9274/1: Add hwcap for Speculative Store Bypassing Safe
ARM: 9273/1: Add hwcap for Speculation Barrier(SB)
ARM: 9272/1: vfp: Add hwcap for FEAT_AA32I8MM
ARM: 9271/1: vfp: Add hwcap for FEAT_AA32BF16
ARM: 9270/1: vfp: Add hwcap for FEAT_FHM
ARM: 9269/1: vfp: Add hwcap for FEAT_DotProd
ARM: 9268/1: vfp: Add hwcap FPHP and ASIMDHP for FEAT_FP16
ARM: 9267/1: Define Armv8 registers in AArch32 state
ARM: findbit: add unwinder information
ARM: findbit: operate by words
ARM: findbit: convert to macros
ARM: findbit: provide more efficient ARMv7 implementation
ARM: findbit: document ARMv5 bit offset calculation
ARM: 9259/1: stacktrace: Convert stacktrace to generic ARCH_STACKWALK
ARM: 9258/1: stacktrace: Make stack walk callback consistent with generic code
ARM: 9265/1: pass -march= only to compiler
...
Diffstat (limited to 'arch/arm/kernel')
-rw-r--r-- | arch/arm/kernel/Makefile | 2 | ||||
-rw-r--r-- | arch/arm/kernel/hyp-stub.S | 2 | ||||
-rw-r--r-- | arch/arm/kernel/machine_kexec.c | 2 | ||||
-rw-r--r-- | arch/arm/kernel/module-plts.c | 14 | ||||
-rw-r--r-- | arch/arm/kernel/perf_callchain.c | 9 | ||||
-rw-r--r-- | arch/arm/kernel/return_address.c | 8 | ||||
-rw-r--r-- | arch/arm/kernel/setup.c | 22 | ||||
-rw-r--r-- | arch/arm/kernel/smp.c | 5 | ||||
-rw-r--r-- | arch/arm/kernel/stacktrace.c | 119 | ||||
-rw-r--r-- | arch/arm/kernel/swp_emulate.c | 1 | ||||
-rw-r--r-- | arch/arm/kernel/traps.c | 25 | ||||
-rw-r--r-- | arch/arm/kernel/unwind.c | 13 |
12 files changed, 111 insertions, 111 deletions
diff --git a/arch/arm/kernel/Makefile b/arch/arm/kernel/Makefile index 48737ec800eb..d53f56d6f840 100644 --- a/arch/arm/kernel/Makefile +++ b/arch/arm/kernel/Makefile @@ -70,7 +70,6 @@ obj-$(CONFIG_HAVE_TCM) += tcm.o obj-$(CONFIG_OF) += devtree.o obj-$(CONFIG_CRASH_DUMP) += crash_dump.o obj-$(CONFIG_SWP_EMULATE) += swp_emulate.o -CFLAGS_swp_emulate.o := -Wa,-march=armv7-a obj-$(CONFIG_HAVE_HW_BREAKPOINT) += hw_breakpoint.o obj-$(CONFIG_CPU_XSCALE) += xscale-cp0.o @@ -99,7 +98,6 @@ CFLAGS_head-inflate-data.o := $(call cc-option,-Wframe-larger-than=10240) obj-$(CONFIG_XIP_DEFLATED_DATA) += head-inflate-data.o obj-$(CONFIG_ARM_VIRT_EXT) += hyp-stub.o -AFLAGS_hyp-stub.o :=-Wa,-march=armv7-a ifeq ($(CONFIG_ARM_PSCI),y) obj-$(CONFIG_SMP) += psci_smp.o endif diff --git a/arch/arm/kernel/hyp-stub.S b/arch/arm/kernel/hyp-stub.S index b699b22a4db1..3a506b9095a5 100644 --- a/arch/arm/kernel/hyp-stub.S +++ b/arch/arm/kernel/hyp-stub.S @@ -9,6 +9,8 @@ #include <asm/assembler.h> #include <asm/virt.h> +.arch armv7-a + #ifndef ZIMAGE /* * For the kernel proper, we need to find out the CPU boot mode long after diff --git a/arch/arm/kernel/machine_kexec.c b/arch/arm/kernel/machine_kexec.c index a2e9ac763a9f..46364b699cc3 100644 --- a/arch/arm/kernel/machine_kexec.c +++ b/arch/arm/kernel/machine_kexec.c @@ -77,6 +77,8 @@ static void machine_crash_nonpanic_core(void *unused) { struct pt_regs regs; + local_fiq_disable(); + crash_setup_regs(®s, get_irq_regs()); printk(KERN_DEBUG "CPU %u will stop doing anything useful since another CPU has crashed\n", smp_processor_id()); diff --git a/arch/arm/kernel/module-plts.c b/arch/arm/kernel/module-plts.c index 1fc309b41f94..af7c322ebed6 100644 --- a/arch/arm/kernel/module-plts.c +++ b/arch/arm/kernel/module-plts.c @@ -284,3 +284,17 @@ int module_frob_arch_sections(Elf_Ehdr *ehdr, Elf_Shdr *sechdrs, mod->arch.core.plt->sh_size, mod->arch.init.plt->sh_size); return 0; } + +bool in_module_plt(unsigned long loc) +{ + struct module *mod; + bool ret; + + preempt_disable(); + mod = __module_text_address(loc); + ret = mod && (loc - (u32)mod->arch.core.plt_ent < mod->arch.core.plt_count * PLT_ENT_SIZE || + loc - (u32)mod->arch.init.plt_ent < mod->arch.init.plt_count * PLT_ENT_SIZE); + preempt_enable(); + + return ret; +} diff --git a/arch/arm/kernel/perf_callchain.c b/arch/arm/kernel/perf_callchain.c index bc6b246ab55e..7147edbe56c6 100644 --- a/arch/arm/kernel/perf_callchain.c +++ b/arch/arm/kernel/perf_callchain.c @@ -81,13 +81,12 @@ perf_callchain_user(struct perf_callchain_entry_ctx *entry, struct pt_regs *regs * whist unwinding the stackframe and is like a subroutine return so we use * the PC. */ -static int -callchain_trace(struct stackframe *fr, - void *data) +static bool +callchain_trace(void *data, unsigned long pc) { struct perf_callchain_entry_ctx *entry = data; - perf_callchain_store(entry, fr->pc); - return 0; + perf_callchain_store(entry, pc); + return true; } void diff --git a/arch/arm/kernel/return_address.c b/arch/arm/kernel/return_address.c index 38f1ea9c724d..ac15db66df4c 100644 --- a/arch/arm/kernel/return_address.c +++ b/arch/arm/kernel/return_address.c @@ -16,17 +16,17 @@ struct return_address_data { void *addr; }; -static int save_return_addr(struct stackframe *frame, void *d) +static bool save_return_addr(void *d, unsigned long pc) { struct return_address_data *data = d; if (!data->level) { - data->addr = (void *)frame->pc; + data->addr = (void *)pc; - return 1; + return false; } else { --data->level; - return 0; + return true; } } diff --git a/arch/arm/kernel/setup.c b/arch/arm/kernel/setup.c index cb88c6e69377..75cd4699e7b3 100644 --- a/arch/arm/kernel/setup.c +++ b/arch/arm/kernel/setup.c @@ -450,6 +450,8 @@ static void __init cpuid_init_hwcaps(void) { int block; u32 isar5; + u32 isar6; + u32 pfr2; if (cpu_architecture() < CPU_ARCH_ARMv7) return; @@ -485,6 +487,18 @@ static void __init cpuid_init_hwcaps(void) block = cpuid_feature_extract_field(isar5, 16); if (block >= 1) elf_hwcap2 |= HWCAP2_CRC32; + + /* Check for Speculation barrier instruction */ + isar6 = read_cpuid_ext(CPUID_EXT_ISAR6); + block = cpuid_feature_extract_field(isar6, 12); + if (block >= 1) + elf_hwcap2 |= HWCAP2_SB; + + /* Check for Speculative Store Bypassing control */ + pfr2 = read_cpuid_ext(CPUID_EXT_PFR2); + block = cpuid_feature_extract_field(pfr2, 4); + if (block >= 1) + elf_hwcap2 |= HWCAP2_SSBS; } static void __init elf_hwcap_fixup(void) @@ -1249,6 +1263,12 @@ static const char *hwcap_str[] = { "vfpd32", "lpae", "evtstrm", + "fphp", + "asimdhp", + "asimddp", + "asimdfhm", + "asimdbf16", + "i8mm", NULL }; @@ -1258,6 +1278,8 @@ static const char *hwcap2_str[] = { "sha1", "sha2", "crc32", + "sb", + "ssbs", NULL }; diff --git a/arch/arm/kernel/smp.c b/arch/arm/kernel/smp.c index 978db2d96b44..36e6efad89f3 100644 --- a/arch/arm/kernel/smp.c +++ b/arch/arm/kernel/smp.c @@ -600,6 +600,8 @@ static DEFINE_RAW_SPINLOCK(stop_lock); */ static void ipi_cpu_stop(unsigned int cpu) { + local_fiq_disable(); + if (system_state <= SYSTEM_RUNNING) { raw_spin_lock(&stop_lock); pr_crit("CPU%u: stopping\n", cpu); @@ -609,9 +611,6 @@ static void ipi_cpu_stop(unsigned int cpu) set_cpu_online(cpu, false); - local_fiq_disable(); - local_irq_disable(); - while (1) { cpu_relax(); wfe(); diff --git a/arch/arm/kernel/stacktrace.c b/arch/arm/kernel/stacktrace.c index 85443b5d1922..620aa82e3bdd 100644 --- a/arch/arm/kernel/stacktrace.c +++ b/arch/arm/kernel/stacktrace.c @@ -127,12 +127,12 @@ int notrace unwind_frame(struct stackframe *frame) #endif void notrace walk_stackframe(struct stackframe *frame, - int (*fn)(struct stackframe *, void *), void *data) + bool (*fn)(void *, unsigned long), void *data) { while (1) { int ret; - if (fn(frame, data)) + if (!fn(data, frame->pc)) break; ret = unwind_frame(frame); if (ret < 0) @@ -142,41 +142,32 @@ void notrace walk_stackframe(struct stackframe *frame, EXPORT_SYMBOL(walk_stackframe); #ifdef CONFIG_STACKTRACE -struct stack_trace_data { - struct stack_trace *trace; - unsigned int no_sched_functions; - unsigned int skip; -}; - -static int save_trace(struct stackframe *frame, void *d) +static void start_stack_trace(struct stackframe *frame, struct task_struct *task, + unsigned long fp, unsigned long sp, + unsigned long lr, unsigned long pc) { - struct stack_trace_data *data = d; - struct stack_trace *trace = data->trace; - unsigned long addr = frame->pc; - - if (data->no_sched_functions && in_sched_functions(addr)) - return 0; - if (data->skip) { - data->skip--; - return 0; - } - - trace->entries[trace->nr_entries++] = addr; - return trace->nr_entries >= trace->max_entries; + frame->fp = fp; + frame->sp = sp; + frame->lr = lr; + frame->pc = pc; +#ifdef CONFIG_KRETPROBES + frame->kr_cur = NULL; + frame->tsk = task; +#endif +#ifdef CONFIG_UNWINDER_FRAME_POINTER + frame->ex_frame = in_entry_text(frame->pc); +#endif } -/* This must be noinline to so that our skip calculation works correctly */ -static noinline void __save_stack_trace(struct task_struct *tsk, - struct stack_trace *trace, unsigned int nosched) +void arch_stack_walk(stack_trace_consume_fn consume_entry, void *cookie, + struct task_struct *task, struct pt_regs *regs) { - struct stack_trace_data data; struct stackframe frame; - data.trace = trace; - data.skip = trace->skip; - data.no_sched_functions = nosched; - - if (tsk != current) { + if (regs) { + start_stack_trace(&frame, NULL, regs->ARM_fp, regs->ARM_sp, + regs->ARM_lr, regs->ARM_pc); + } else if (task != current) { #ifdef CONFIG_SMP /* * What guarantees do we have here that 'tsk' is not @@ -185,64 +176,22 @@ static noinline void __save_stack_trace(struct task_struct *tsk, */ return; #else - frame.fp = thread_saved_fp(tsk); - frame.sp = thread_saved_sp(tsk); - frame.lr = 0; /* recovered from the stack */ - frame.pc = thread_saved_pc(tsk); + start_stack_trace(&frame, task, thread_saved_fp(task), + thread_saved_sp(task), 0, + thread_saved_pc(task)); #endif } else { - /* We don't want this function nor the caller */ - data.skip += 2; - frame.fp = (unsigned long)__builtin_frame_address(0); - frame.sp = current_stack_pointer; - frame.lr = (unsigned long)__builtin_return_address(0); here: - frame.pc = (unsigned long)&&here; + start_stack_trace(&frame, task, + (unsigned long)__builtin_frame_address(0), + current_stack_pointer, + (unsigned long)__builtin_return_address(0), + (unsigned long)&&here); + /* skip this function */ + if (unwind_frame(&frame)) + return; } -#ifdef CONFIG_KRETPROBES - frame.kr_cur = NULL; - frame.tsk = tsk; -#endif -#ifdef CONFIG_UNWINDER_FRAME_POINTER - frame.ex_frame = false; -#endif - - walk_stackframe(&frame, save_trace, &data); -} - -void save_stack_trace_regs(struct pt_regs *regs, struct stack_trace *trace) -{ - struct stack_trace_data data; - struct stackframe frame; - - data.trace = trace; - data.skip = trace->skip; - data.no_sched_functions = 0; - - frame.fp = regs->ARM_fp; - frame.sp = regs->ARM_sp; - frame.lr = regs->ARM_lr; - frame.pc = regs->ARM_pc; -#ifdef CONFIG_KRETPROBES - frame.kr_cur = NULL; - frame.tsk = current; -#endif -#ifdef CONFIG_UNWINDER_FRAME_POINTER - frame.ex_frame = in_entry_text(frame.pc); -#endif - - walk_stackframe(&frame, save_trace, &data); -} -void save_stack_trace_tsk(struct task_struct *tsk, struct stack_trace *trace) -{ - __save_stack_trace(tsk, trace, 1); -} -EXPORT_SYMBOL(save_stack_trace_tsk); - -void save_stack_trace(struct stack_trace *trace) -{ - __save_stack_trace(current, trace, 0); + walk_stackframe(&frame, consume_entry, cookie); } -EXPORT_SYMBOL_GPL(save_stack_trace); #endif diff --git a/arch/arm/kernel/swp_emulate.c b/arch/arm/kernel/swp_emulate.c index b74bfcf94fb1..fdce83c95acb 100644 --- a/arch/arm/kernel/swp_emulate.c +++ b/arch/arm/kernel/swp_emulate.c @@ -34,6 +34,7 @@ */ #define __user_swpX_asm(data, addr, res, temp, B) \ __asm__ __volatile__( \ + ".arch armv7-a\n" \ "0: ldrex"B" %2, [%3]\n" \ "1: strex"B" %0, %1, [%3]\n" \ " cmp %0, #0\n" \ diff --git a/arch/arm/kernel/traps.c b/arch/arm/kernel/traps.c index 20b2db6dcd1c..40c7c807d67f 100644 --- a/arch/arm/kernel/traps.c +++ b/arch/arm/kernel/traps.c @@ -178,19 +178,22 @@ static void dump_instr(const char *lvl, struct pt_regs *regs) for (i = -4; i < 1 + !!thumb; i++) { unsigned int val, bad; - if (!user_mode(regs)) { - if (thumb) { - u16 val16; - bad = get_kernel_nofault(val16, &((u16 *)addr)[i]); - val = val16; - } else { - bad = get_kernel_nofault(val, &((u32 *)addr)[i]); - } + if (thumb) { + u16 tmp; + + if (user_mode(regs)) + bad = get_user(tmp, &((u16 __user *)addr)[i]); + else + bad = get_kernel_nofault(tmp, &((u16 *)addr)[i]); + + val = __mem_to_opcode_thumb16(tmp); } else { - if (thumb) - bad = get_user(val, &((u16 *)addr)[i]); + if (user_mode(regs)) + bad = get_user(val, &((u32 __user *)addr)[i]); else - bad = get_user(val, &((u32 *)addr)[i]); + bad = get_kernel_nofault(val, &((u32 *)addr)[i]); + + val = __mem_to_opcode_arm(val); } if (!bad) diff --git a/arch/arm/kernel/unwind.c b/arch/arm/kernel/unwind.c index a37ea6c772cd..53be7ea6181b 100644 --- a/arch/arm/kernel/unwind.c +++ b/arch/arm/kernel/unwind.c @@ -28,6 +28,7 @@ #include <linux/slab.h> #include <linux/spinlock.h> #include <linux/list.h> +#include <linux/module.h> #include <asm/stacktrace.h> #include <asm/traps.h> @@ -395,8 +396,18 @@ int unwind_frame(struct stackframe *frame) idx = unwind_find_idx(frame->pc); if (!idx) { - if (frame->pc && kernel_text_address(frame->pc)) + if (frame->pc && kernel_text_address(frame->pc)) { + if (in_module_plt(frame->pc) && frame->pc != frame->lr) { + /* + * Quoting Ard: Veneers only set PC using a + * PC+immediate LDR, and so they don't affect + * the state of the stack or the register file + */ + frame->pc = frame->lr; + return URC_OK; + } pr_warn("unwind: Index not found %08lx\n", frame->pc); + } return -URC_FAILURE; } |