1d2912cb1SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
21da177e4SLinus Torvalds /*
31da177e4SLinus Torvalds * linux/arch/arm/kernel/traps.c
41da177e4SLinus Torvalds *
5ab72b007SRussell King * Copyright (C) 1995-2009 Russell King
61da177e4SLinus Torvalds * Fragments that appear the same as linux/arch/i386/kernel/traps.c (C) Linus Torvalds
71da177e4SLinus Torvalds *
81da177e4SLinus Torvalds * 'traps.c' handles hardware exceptions after we have saved some state in
91da177e4SLinus Torvalds * 'linux/arch/arm/lib/traps.S'. Mostly a debugging aid, but will probably
101da177e4SLinus Torvalds * kill the offending process.
111da177e4SLinus Torvalds */
121da177e4SLinus Torvalds #include <linux/signal.h>
131da177e4SLinus Torvalds #include <linux/personality.h>
141da177e4SLinus Torvalds #include <linux/kallsyms.h>
15a9221de6SRussell King #include <linux/spinlock.h>
1633fa9b13SRussell King #include <linux/uaccess.h>
17a9221de6SRussell King #include <linux/hardirq.h>
18a9221de6SRussell King #include <linux/kdebug.h>
19eb0146daSMasami Hiramatsu #include <linux/kprobes.h>
20a9221de6SRussell King #include <linux/module.h>
21a9221de6SRussell King #include <linux/kexec.h>
2287e040b6SSimon Glass #include <linux/bug.h>
23a9221de6SRussell King #include <linux/delay.h>
24a9221de6SRussell King #include <linux/init.h>
253f07c014SIngo Molnar #include <linux/sched/signal.h>
26b17b0153SIngo Molnar #include <linux/sched/debug.h>
2768db0cf1SIngo Molnar #include <linux/sched/task_stack.h>
28c0e7f7eeSDaniel Thompson #include <linux/irq.h>
291da177e4SLinus Torvalds
3060063497SArun Sharma #include <linux/atomic.h>
311da177e4SLinus Torvalds #include <asm/cacheflush.h>
325a567d78SJamie Iles #include <asm/exception.h>
33b9baf5c8SRussell King (Oracle) #include <asm/spectre.h>
341da177e4SLinus Torvalds #include <asm/unistd.h>
351da177e4SLinus Torvalds #include <asm/traps.h>
3649432d4aSNikolay Borisov #include <asm/ptrace.h>
37bff595c1SCatalin Marinas #include <asm/unwind.h>
38f159f4edSTony Lindgren #include <asm/tls.h>
398cdfdf7fSArd Biesheuvel #include <asm/stacktrace.h>
409f97da78SDavid Howells #include <asm/system_misc.h>
41a79a0cb1SBen Dooks #include <asm/opcodes.h>
421da177e4SLinus Torvalds
4349432d4aSNikolay Borisov
4429c350bfSRussell King static const char *handler[]= {
4529c350bfSRussell King "prefetch abort",
4629c350bfSRussell King "data abort",
4729c350bfSRussell King "address exception",
4829c350bfSRussell King "interrupt",
4929c350bfSRussell King "undefined instruction",
5029c350bfSRussell King };
511da177e4SLinus Torvalds
52247055aaSCatalin Marinas void *vectors_page;
53247055aaSCatalin Marinas
541da177e4SLinus Torvalds #ifdef CONFIG_DEBUG_USER
551da177e4SLinus Torvalds unsigned int user_debug;
561da177e4SLinus Torvalds
user_debug_setup(char * str)571da177e4SLinus Torvalds static int __init user_debug_setup(char *str)
581da177e4SLinus Torvalds {
591da177e4SLinus Torvalds get_option(&str, &user_debug);
601da177e4SLinus Torvalds return 1;
611da177e4SLinus Torvalds }
621da177e4SLinus Torvalds __setup("user_debug=", user_debug_setup);
631da177e4SLinus Torvalds #endif
641da177e4SLinus Torvalds
dump_backtrace_entry(unsigned long where,unsigned long from,unsigned long frame,const char * loglvl)655489ab50SDmitry Safonov void dump_backtrace_entry(unsigned long where, unsigned long from,
665489ab50SDmitry Safonov unsigned long frame, const char *loglvl)
671da177e4SLinus Torvalds {
6840ff1ddbSVincent Whitchurch unsigned long end = frame + 4 + sizeof(struct pt_regs);
6940ff1ddbSVincent Whitchurch
70d4664b6cSArd Biesheuvel if (IS_ENABLED(CONFIG_UNWINDER_FRAME_POINTER) &&
71d4664b6cSArd Biesheuvel IS_ENABLED(CONFIG_CC_IS_GCC) &&
72d4664b6cSArd Biesheuvel end > ALIGN(frame, THREAD_SIZE)) {
73d4664b6cSArd Biesheuvel /*
74d4664b6cSArd Biesheuvel * If we are walking past the end of the stack, it may be due
75d4664b6cSArd Biesheuvel * to the fact that we are on an IRQ or overflow stack. In this
76d4664b6cSArd Biesheuvel * case, we can load the address of the other stack from the
77d4664b6cSArd Biesheuvel * frame record.
78d4664b6cSArd Biesheuvel */
79d4664b6cSArd Biesheuvel frame = ((unsigned long *)frame)[-2] - 4;
80d4664b6cSArd Biesheuvel end = frame + 4 + sizeof(struct pt_regs);
81d4664b6cSArd Biesheuvel }
82d4664b6cSArd Biesheuvel
83b0343ab3SRussell King #ifndef CONFIG_KALLSYMS
84b0343ab3SRussell King printk("%sFunction entered at [<%08lx>] from [<%08lx>]\n",
85b0343ab3SRussell King loglvl, where, from);
86b0343ab3SRussell King #elif defined CONFIG_BACKTRACE_VERBOSE
8734135eacSDmitry Safonov printk("%s[<%08lx>] (%ps) from [<%08lx>] (%pS)\n",
8834135eacSDmitry Safonov loglvl, where, (void *)where, from, (void *)from);
891da177e4SLinus Torvalds #else
90b0343ab3SRussell King printk("%s %ps from %pS\n", loglvl, (void *)where, (void *)from);
911da177e4SLinus Torvalds #endif
927ab3f8d5SRussell King
9340ff1ddbSVincent Whitchurch if (in_entry_text(from) && end <= ALIGN(frame, THREAD_SIZE))
9434135eacSDmitry Safonov dump_mem(loglvl, "Exception stack", frame + 4, end);
951da177e4SLinus Torvalds }
961da177e4SLinus Torvalds
dump_backtrace_stm(u32 * stack,u32 instruction,const char * loglvl)975489ab50SDmitry Safonov void dump_backtrace_stm(u32 *stack, u32 instruction, const char *loglvl)
9824c66dfdSRussell King {
9924c66dfdSRussell King char str[80], *p;
10024c66dfdSRussell King unsigned int x;
10124c66dfdSRussell King int reg;
10224c66dfdSRussell King
10324c66dfdSRussell King for (reg = 10, x = 0, p = str; reg >= 0; reg--) {
10424c66dfdSRussell King if (instruction & BIT(reg)) {
10524c66dfdSRussell King p += sprintf(p, " r%d:%08x", reg, *stack--);
10624c66dfdSRussell King if (++x == 6) {
10724c66dfdSRussell King x = 0;
10824c66dfdSRussell King p = str;
10934135eacSDmitry Safonov printk("%s%s\n", loglvl, str);
11024c66dfdSRussell King }
11124c66dfdSRussell King }
11224c66dfdSRussell King }
11324c66dfdSRussell King if (p != str)
11434135eacSDmitry Safonov printk("%s%s\n", loglvl, str);
11524c66dfdSRussell King }
11624c66dfdSRussell King
117bff595c1SCatalin Marinas #ifndef CONFIG_ARM_UNWIND
1181da177e4SLinus Torvalds /*
1191da177e4SLinus Torvalds * Stack pointers should always be within the kernels view of
1201da177e4SLinus Torvalds * physical memory. If it is not there, then we can't dump
1211da177e4SLinus Torvalds * out any information relating to the stack.
1221da177e4SLinus Torvalds */
verify_stack(unsigned long sp)1231da177e4SLinus Torvalds static int verify_stack(unsigned long sp)
1241da177e4SLinus Torvalds {
12509d9bae0SRussell King if (sp < PAGE_OFFSET ||
126a1c510d0SArd Biesheuvel (!IS_ENABLED(CONFIG_VMAP_STACK) &&
127a1c510d0SArd Biesheuvel sp > (unsigned long)high_memory && high_memory != NULL))
1281da177e4SLinus Torvalds return -EFAULT;
1291da177e4SLinus Torvalds
1301da177e4SLinus Torvalds return 0;
1311da177e4SLinus Torvalds }
132bff595c1SCatalin Marinas #endif
1331da177e4SLinus Torvalds
1341da177e4SLinus Torvalds /*
1351da177e4SLinus Torvalds * Dump out the contents of some memory nicely...
1361da177e4SLinus Torvalds */
dump_mem(const char * lvl,const char * str,unsigned long bottom,unsigned long top)1378cdfdf7fSArd Biesheuvel void dump_mem(const char *lvl, const char *str, unsigned long bottom,
138e40c2ec6SRussell King unsigned long top)
1391da177e4SLinus Torvalds {
140d191fe09SRussell King unsigned long first;
1411da177e4SLinus Torvalds int i;
1421da177e4SLinus Torvalds
143e40c2ec6SRussell King printk("%s%s(0x%08lx to 0x%08lx)\n", lvl, str, bottom, top);
1441da177e4SLinus Torvalds
145d191fe09SRussell King for (first = bottom & ~31; first < top; first += 32) {
146d191fe09SRussell King unsigned long p;
147d191fe09SRussell King char str[sizeof(" 12345678") * 8 + 1];
1481da177e4SLinus Torvalds
149d191fe09SRussell King memset(str, ' ', sizeof(str));
150d191fe09SRussell King str[sizeof(str) - 1] = '\0';
1511da177e4SLinus Torvalds
152d191fe09SRussell King for (p = first, i = 0; i < 8 && p < top; i++, p += 4) {
153d191fe09SRussell King if (p >= bottom && p < top) {
154d191fe09SRussell King unsigned long val;
15500d43d13SArd Biesheuvel if (!get_kernel_nofault(val, (unsigned long *)p))
156d191fe09SRussell King sprintf(str + i * 9, " %08lx", val);
157d191fe09SRussell King else
158d191fe09SRussell King sprintf(str + i * 9, " ????????");
1591da177e4SLinus Torvalds }
1601da177e4SLinus Torvalds }
161e40c2ec6SRussell King printk("%s%04lx:%s\n", lvl, first & 0xffff, str);
1621da177e4SLinus Torvalds }
1631da177e4SLinus Torvalds }
1641da177e4SLinus Torvalds
dump_instr(const char * lvl,struct pt_regs * regs)165344179fcSArnd Bergmann static void dump_instr(const char *lvl, struct pt_regs *regs)
1661da177e4SLinus Torvalds {
1671da177e4SLinus Torvalds unsigned long addr = instruction_pointer(regs);
1681da177e4SLinus Torvalds const int thumb = thumb_mode(regs);
1691da177e4SLinus Torvalds const int width = thumb ? 4 : 8;
170d191fe09SRussell King char str[sizeof("00000000 ") * 5 + 2 + 1], *p = str;
1711da177e4SLinus Torvalds int i;
1721da177e4SLinus Torvalds
1731da177e4SLinus Torvalds /*
174b9dd05c7SMark Rutland * Note that we now dump the code first, just in case the backtrace
175b9dd05c7SMark Rutland * kills us.
1761da177e4SLinus Torvalds */
1771da177e4SLinus Torvalds
178a9011580SRussell King for (i = -4; i < 1 + !!thumb; i++) {
1791da177e4SLinus Torvalds unsigned int val, bad;
1801da177e4SLinus Torvalds
181344179fcSArnd Bergmann if (thumb) {
18221d0798aSZhen Lei u16 tmp;
18321d0798aSZhen Lei
18421d0798aSZhen Lei if (user_mode(regs))
18521d0798aSZhen Lei bad = get_user(tmp, &((u16 __user *)addr)[i]);
1861da177e4SLinus Torvalds else
18721d0798aSZhen Lei bad = get_kernel_nofault(tmp, &((u16 *)addr)[i]);
18821d0798aSZhen Lei
189ba290d4fSZhen Lei val = __mem_to_opcode_thumb16(tmp);
19021d0798aSZhen Lei } else {
19121d0798aSZhen Lei if (user_mode(regs))
19221d0798aSZhen Lei bad = get_user(val, &((u32 __user *)addr)[i]);
19321d0798aSZhen Lei else
19421d0798aSZhen Lei bad = get_kernel_nofault(val, &((u32 *)addr)[i]);
195ba290d4fSZhen Lei
196ba290d4fSZhen Lei val = __mem_to_opcode_arm(val);
197344179fcSArnd Bergmann }
1981da177e4SLinus Torvalds
1991da177e4SLinus Torvalds if (!bad)
200d191fe09SRussell King p += sprintf(p, i == 0 ? "(%0*x) " : "%0*x ",
201d191fe09SRussell King width, val);
2021da177e4SLinus Torvalds else {
203d191fe09SRussell King p += sprintf(p, "bad PC value");
2041da177e4SLinus Torvalds break;
2051da177e4SLinus Torvalds }
2061da177e4SLinus Torvalds }
207e40c2ec6SRussell King printk("%sCode: %s\n", lvl, str);
208b9dd05c7SMark Rutland }
2091da177e4SLinus Torvalds
210bff595c1SCatalin Marinas #ifdef CONFIG_ARM_UNWIND
dump_backtrace(struct pt_regs * regs,struct task_struct * tsk,const char * loglvl)21109cffecaSZhen Lei void dump_backtrace(struct pt_regs *regs, struct task_struct *tsk,
212ee65ca01SDmitry Safonov const char *loglvl)
213bff595c1SCatalin Marinas {
214ee65ca01SDmitry Safonov unwind_backtrace(regs, tsk, loglvl);
215bff595c1SCatalin Marinas }
216bff595c1SCatalin Marinas #else
dump_backtrace(struct pt_regs * regs,struct task_struct * tsk,const char * loglvl)21709cffecaSZhen Lei void dump_backtrace(struct pt_regs *regs, struct task_struct *tsk,
218ee65ca01SDmitry Safonov const char *loglvl)
2191da177e4SLinus Torvalds {
22067a94c23SCatalin Marinas unsigned int fp, mode;
2211da177e4SLinus Torvalds int ok = 1;
2221da177e4SLinus Torvalds
223ee65ca01SDmitry Safonov printk("%sBacktrace: ", loglvl);
22467a94c23SCatalin Marinas
22567a94c23SCatalin Marinas if (!tsk)
22667a94c23SCatalin Marinas tsk = current;
22767a94c23SCatalin Marinas
22867a94c23SCatalin Marinas if (regs) {
22949432d4aSNikolay Borisov fp = frame_pointer(regs);
23067a94c23SCatalin Marinas mode = processor_mode(regs);
23167a94c23SCatalin Marinas } else if (tsk != current) {
23267a94c23SCatalin Marinas fp = thread_saved_fp(tsk);
23367a94c23SCatalin Marinas mode = 0x10;
23467a94c23SCatalin Marinas } else {
23567a94c23SCatalin Marinas asm("mov %0, fp" : "=r" (fp) : : "cc");
23667a94c23SCatalin Marinas mode = 0x10;
23767a94c23SCatalin Marinas }
23867a94c23SCatalin Marinas
2391da177e4SLinus Torvalds if (!fp) {
2404ed89f22SRussell King pr_cont("no frame pointer");
2411da177e4SLinus Torvalds ok = 0;
2421da177e4SLinus Torvalds } else if (verify_stack(fp)) {
2434ed89f22SRussell King pr_cont("invalid frame pointer 0x%08x", fp);
2441da177e4SLinus Torvalds ok = 0;
24555205823SAl Viro } else if (fp < (unsigned long)end_of_stack(tsk))
2464ed89f22SRussell King pr_cont("frame pointer underflow");
2474ed89f22SRussell King pr_cont("\n");
2481da177e4SLinus Torvalds
2491da177e4SLinus Torvalds if (ok)
250ee65ca01SDmitry Safonov c_backtrace(fp, mode, loglvl);
2511da177e4SLinus Torvalds }
252bff595c1SCatalin Marinas #endif
2531da177e4SLinus Torvalds
show_stack(struct task_struct * tsk,unsigned long * sp,const char * loglvl)2549cb8f069SDmitry Safonov void show_stack(struct task_struct *tsk, unsigned long *sp, const char *loglvl)
255a4502d04SDmitry Safonov {
256a4502d04SDmitry Safonov dump_backtrace(NULL, tsk, loglvl);
257a4502d04SDmitry Safonov barrier();
258a4502d04SDmitry Safonov }
259a4502d04SDmitry Safonov
260d9202429SRussell King #ifdef CONFIG_PREEMPT
261d9202429SRussell King #define S_PREEMPT " PREEMPT"
262e7289c6dSThomas Gleixner #elif defined(CONFIG_PREEMPT_RT)
263e7289c6dSThomas Gleixner #define S_PREEMPT " PREEMPT_RT"
264d9202429SRussell King #else
265d9202429SRussell King #define S_PREEMPT ""
266d9202429SRussell King #endif
267d9202429SRussell King #ifdef CONFIG_SMP
268d9202429SRussell King #define S_SMP " SMP"
269d9202429SRussell King #else
270d9202429SRussell King #define S_SMP ""
271d9202429SRussell King #endif
2728211ca65SRussell King #ifdef CONFIG_THUMB2_KERNEL
2738211ca65SRussell King #define S_ISA " THUMB2"
2748211ca65SRussell King #else
2758211ca65SRussell King #define S_ISA " ARM"
2768211ca65SRussell King #endif
277d9202429SRussell King
__die(const char * str,int err,struct pt_regs * regs)27802df19b4SRabin Vincent static int __die(const char *str, int err, struct pt_regs *regs)
2791da177e4SLinus Torvalds {
28002df19b4SRabin Vincent struct task_struct *tsk = current;
2811da177e4SLinus Torvalds static int die_counter;
282a9221de6SRussell King int ret;
2831da177e4SLinus Torvalds
2844ed89f22SRussell King pr_emerg("Internal error: %s: %x [#%d]" S_PREEMPT S_SMP S_ISA "\n",
2854ed89f22SRussell King str, err, ++die_counter);
286a9221de6SRussell King
287a9221de6SRussell King /* trap and error numbers are mostly meaningless on ARM */
288a9221de6SRussell King ret = notify_die(DIE_OOPS, str, regs, err, tsk->thread.trap_no, SIGSEGV);
289a9221de6SRussell King if (ret == NOTIFY_STOP)
29002df19b4SRabin Vincent return 1;
291a9221de6SRussell King
2921da177e4SLinus Torvalds print_modules();
293652a12efSRussell King __show_regs(regs);
2945aa6b70eSManinder Singh __show_regs_alloc_free(regs);
2954ed89f22SRussell King pr_emerg("Process %.*s (pid: %d, stack limit = 0x%p)\n",
29602df19b4SRabin Vincent TASK_COMM_LEN, tsk->comm, task_pid_nr(tsk), end_of_stack(tsk));
2971da177e4SLinus Torvalds
2981da177e4SLinus Torvalds if (!user_mode(regs) || in_interrupt()) {
299e40c2ec6SRussell King dump_mem(KERN_EMERG, "Stack: ", regs->ARM_sp,
300a1c510d0SArd Biesheuvel ALIGN(regs->ARM_sp - THREAD_SIZE, THREAD_ALIGN)
301a1c510d0SArd Biesheuvel + THREAD_SIZE);
302ee65ca01SDmitry Safonov dump_backtrace(regs, tsk, KERN_EMERG);
303e40c2ec6SRussell King dump_instr(KERN_EMERG, regs);
3041da177e4SLinus Torvalds }
305a9221de6SRussell King
30602df19b4SRabin Vincent return 0;
307d362979aSRussell King }
3081da177e4SLinus Torvalds
30902df19b4SRabin Vincent static arch_spinlock_t die_lock = __ARCH_SPIN_LOCK_UNLOCKED;
31002df19b4SRabin Vincent static int die_owner = -1;
31102df19b4SRabin Vincent static unsigned int die_nest_count;
312d362979aSRussell King
oops_begin(void)31302df19b4SRabin Vincent static unsigned long oops_begin(void)
314d362979aSRussell King {
31502df19b4SRabin Vincent int cpu;
31602df19b4SRabin Vincent unsigned long flags;
317d362979aSRussell King
318d9202429SRussell King oops_enter();
319d9202429SRussell King
32002df19b4SRabin Vincent /* racy, but better than risking deadlock. */
32102df19b4SRabin Vincent raw_local_irq_save(flags);
32202df19b4SRabin Vincent cpu = smp_processor_id();
32302df19b4SRabin Vincent if (!arch_spin_trylock(&die_lock)) {
32402df19b4SRabin Vincent if (cpu == die_owner)
32502df19b4SRabin Vincent /* nested oops. should stop eventually */;
32602df19b4SRabin Vincent else
32702df19b4SRabin Vincent arch_spin_lock(&die_lock);
32802df19b4SRabin Vincent }
32902df19b4SRabin Vincent die_nest_count++;
33002df19b4SRabin Vincent die_owner = cpu;
33103a6e5bdSRussell King console_verbose();
332d362979aSRussell King bust_spinlocks(1);
33302df19b4SRabin Vincent return flags;
33402df19b4SRabin Vincent }
335a9221de6SRussell King
oops_end(unsigned long flags,struct pt_regs * regs,int signr)33602df19b4SRabin Vincent static void oops_end(unsigned long flags, struct pt_regs *regs, int signr)
33702df19b4SRabin Vincent {
33802df19b4SRabin Vincent if (regs && kexec_should_crash(current))
339a9221de6SRussell King crash_kexec(regs);
340a9221de6SRussell King
3411da177e4SLinus Torvalds bust_spinlocks(0);
34202df19b4SRabin Vincent die_owner = -1;
343373d4d09SRusty Russell add_taint(TAINT_DIE, LOCKDEP_NOW_UNRELIABLE);
34402df19b4SRabin Vincent die_nest_count--;
34502df19b4SRabin Vincent if (!die_nest_count)
34602df19b4SRabin Vincent /* Nest count reaches zero, release the lock. */
34702df19b4SRabin Vincent arch_spin_unlock(&die_lock);
34802df19b4SRabin Vincent raw_local_irq_restore(flags);
34903a6e5bdSRussell King oops_exit();
35031867499SRussell King
351d9202429SRussell King if (in_interrupt())
352d9202429SRussell King panic("Fatal exception in interrupt");
353cea6a4baSHorms if (panic_on_oops)
354012c437dSHorms panic("Fatal exception");
35502df19b4SRabin Vincent if (signr)
3560e25498fSEric W. Biederman make_task_dead(signr);
35702df19b4SRabin Vincent }
35802df19b4SRabin Vincent
35902df19b4SRabin Vincent /*
36002df19b4SRabin Vincent * This function is protected against re-entrancy.
36102df19b4SRabin Vincent */
die(const char * str,struct pt_regs * regs,int err)36202df19b4SRabin Vincent void die(const char *str, struct pt_regs *regs, int err)
36302df19b4SRabin Vincent {
36402df19b4SRabin Vincent enum bug_trap_type bug_type = BUG_TRAP_TYPE_NONE;
36502df19b4SRabin Vincent unsigned long flags = oops_begin();
36602df19b4SRabin Vincent int sig = SIGSEGV;
36702df19b4SRabin Vincent
36802df19b4SRabin Vincent if (!user_mode(regs))
36902df19b4SRabin Vincent bug_type = report_bug(regs->ARM_pc, regs);
37002df19b4SRabin Vincent if (bug_type != BUG_TRAP_TYPE_NONE)
37102df19b4SRabin Vincent str = "Oops - BUG";
37202df19b4SRabin Vincent
37302df19b4SRabin Vincent if (__die(str, err, regs))
37402df19b4SRabin Vincent sig = 0;
37502df19b4SRabin Vincent
37602df19b4SRabin Vincent oops_end(flags, regs, sig);
3771da177e4SLinus Torvalds }
3781da177e4SLinus Torvalds
arm_notify_die(const char * str,struct pt_regs * regs,int signo,int si_code,void __user * addr,unsigned long err,unsigned long trap)3791eeb66a1SChristoph Hellwig void arm_notify_die(const char *str, struct pt_regs *regs,
38005e792e3SEric W. Biederman int signo, int si_code, void __user *addr,
38105e792e3SEric W. Biederman unsigned long err, unsigned long trap)
3821da177e4SLinus Torvalds {
3831da177e4SLinus Torvalds if (user_mode(regs)) {
3841da177e4SLinus Torvalds current->thread.error_code = err;
3851da177e4SLinus Torvalds current->thread.trap_no = trap;
3861da177e4SLinus Torvalds
3872e1661d2SEric W. Biederman force_sig_fault(signo, si_code, addr);
3881da177e4SLinus Torvalds } else {
3891da177e4SLinus Torvalds die(str, regs, err);
3901da177e4SLinus Torvalds }
3911da177e4SLinus Torvalds }
3921da177e4SLinus Torvalds
39387e040b6SSimon Glass #ifdef CONFIG_GENERIC_BUG
39487e040b6SSimon Glass
is_valid_bugaddr(unsigned long pc)39587e040b6SSimon Glass int is_valid_bugaddr(unsigned long pc)
39687e040b6SSimon Glass {
39787e040b6SSimon Glass #ifdef CONFIG_THUMB2_KERNEL
39863328070SBen Dooks u16 bkpt;
39963328070SBen Dooks u16 insn = __opcode_to_mem_thumb16(BUG_INSTR_VALUE);
40087e040b6SSimon Glass #else
40163328070SBen Dooks u32 bkpt;
40263328070SBen Dooks u32 insn = __opcode_to_mem_arm(BUG_INSTR_VALUE);
40387e040b6SSimon Glass #endif
40487e040b6SSimon Glass
4050c389d89SLinus Torvalds if (get_kernel_nofault(bkpt, (void *)pc))
40687e040b6SSimon Glass return 0;
40787e040b6SSimon Glass
40863328070SBen Dooks return bkpt == insn;
40987e040b6SSimon Glass }
41087e040b6SSimon Glass
41187e040b6SSimon Glass #endif
41287e040b6SSimon Glass
4131da177e4SLinus Torvalds static LIST_HEAD(undef_hook);
414bd31b859SThomas Gleixner static DEFINE_RAW_SPINLOCK(undef_lock);
4151da177e4SLinus Torvalds
register_undef_hook(struct undef_hook * hook)4161da177e4SLinus Torvalds void register_undef_hook(struct undef_hook *hook)
4171da177e4SLinus Torvalds {
418109d89caSRussell King unsigned long flags;
419109d89caSRussell King
420bd31b859SThomas Gleixner raw_spin_lock_irqsave(&undef_lock, flags);
4211da177e4SLinus Torvalds list_add(&hook->node, &undef_hook);
422bd31b859SThomas Gleixner raw_spin_unlock_irqrestore(&undef_lock, flags);
4231da177e4SLinus Torvalds }
4241da177e4SLinus Torvalds
unregister_undef_hook(struct undef_hook * hook)4251da177e4SLinus Torvalds void unregister_undef_hook(struct undef_hook *hook)
4261da177e4SLinus Torvalds {
427109d89caSRussell King unsigned long flags;
428109d89caSRussell King
429bd31b859SThomas Gleixner raw_spin_lock_irqsave(&undef_lock, flags);
4301da177e4SLinus Torvalds list_del(&hook->node);
431bd31b859SThomas Gleixner raw_spin_unlock_irqrestore(&undef_lock, flags);
4321da177e4SLinus Torvalds }
4331da177e4SLinus Torvalds
434eb0146daSMasami Hiramatsu static nokprobe_inline
call_undef_hook(struct pt_regs * regs,unsigned int instr)435eb0146daSMasami Hiramatsu int call_undef_hook(struct pt_regs *regs, unsigned int instr)
436b03a5b75SRussell King {
437b03a5b75SRussell King struct undef_hook *hook;
438b03a5b75SRussell King unsigned long flags;
439b03a5b75SRussell King int (*fn)(struct pt_regs *regs, unsigned int instr) = NULL;
440b03a5b75SRussell King
441bd31b859SThomas Gleixner raw_spin_lock_irqsave(&undef_lock, flags);
442b03a5b75SRussell King list_for_each_entry(hook, &undef_hook, node)
443b03a5b75SRussell King if ((instr & hook->instr_mask) == hook->instr_val &&
444b03a5b75SRussell King (regs->ARM_cpsr & hook->cpsr_mask) == hook->cpsr_val)
445b03a5b75SRussell King fn = hook->fn;
446bd31b859SThomas Gleixner raw_spin_unlock_irqrestore(&undef_lock, flags);
447b03a5b75SRussell King
448b03a5b75SRussell King return fn ? fn(regs, instr) : 1;
449b03a5b75SRussell King }
450b03a5b75SRussell King
do_undefinstr(struct pt_regs * regs)451c6089061SRussell King asmlinkage void do_undefinstr(struct pt_regs *regs)
4521da177e4SLinus Torvalds {
4531da177e4SLinus Torvalds unsigned int instr;
4541da177e4SLinus Torvalds void __user *pc;
4551da177e4SLinus Torvalds
4561da177e4SLinus Torvalds pc = (void __user *)instruction_pointer(regs);
457dfc544c7SDan Williams
458dfc544c7SDan Williams if (processor_mode(regs) == SVC_MODE) {
459592201a9SJon Medhurst #ifdef CONFIG_THUMB2_KERNEL
460592201a9SJon Medhurst if (thumb_mode(regs)) {
461a79a0cb1SBen Dooks instr = __mem_to_opcode_thumb16(((u16 *)pc)[0]);
462592201a9SJon Medhurst if (is_wide_instruction(instr)) {
463a79a0cb1SBen Dooks u16 inst2;
464a79a0cb1SBen Dooks inst2 = __mem_to_opcode_thumb16(((u16 *)pc)[1]);
465a79a0cb1SBen Dooks instr = __opcode_thumb32_compose(instr, inst2);
466592201a9SJon Medhurst }
467592201a9SJon Medhurst } else
468592201a9SJon Medhurst #endif
469a79a0cb1SBen Dooks instr = __mem_to_opcode_arm(*(u32 *) pc);
470dfc544c7SDan Williams } else if (thumb_mode(regs)) {
4712b2040afSWill Deacon if (get_user(instr, (u16 __user *)pc))
4722b2040afSWill Deacon goto die_sig;
473a79a0cb1SBen Dooks instr = __mem_to_opcode_thumb16(instr);
474592201a9SJon Medhurst if (is_wide_instruction(instr)) {
475592201a9SJon Medhurst unsigned int instr2;
4762b2040afSWill Deacon if (get_user(instr2, (u16 __user *)pc+1))
4772b2040afSWill Deacon goto die_sig;
478a79a0cb1SBen Dooks instr2 = __mem_to_opcode_thumb16(instr2);
479a79a0cb1SBen Dooks instr = __opcode_thumb32_compose(instr, instr2);
480592201a9SJon Medhurst }
481d6cd9894STaras Kondratiuk } else {
482d6cd9894STaras Kondratiuk if (get_user(instr, (u32 __user *)pc))
4832b2040afSWill Deacon goto die_sig;
484d6cd9894STaras Kondratiuk instr = __mem_to_opcode_arm(instr);
4851da177e4SLinus Torvalds }
4861da177e4SLinus Torvalds
487b03a5b75SRussell King if (call_undef_hook(regs, instr) == 0)
4881da177e4SLinus Torvalds return;
4891da177e4SLinus Torvalds
4902b2040afSWill Deacon die_sig:
4911da177e4SLinus Torvalds #ifdef CONFIG_DEBUG_USER
4921da177e4SLinus Torvalds if (user_debug & UDBG_UNDEFINED) {
493ee50036bSBaruch Siach pr_info("%s (%d): undefined instruction: pc=%px\n",
49419c5870cSAlexey Dobriyan current->comm, task_pid_nr(current), pc);
495b5b6b5f5SRussell King __show_regs(regs);
496e40c2ec6SRussell King dump_instr(KERN_INFO, regs);
4971da177e4SLinus Torvalds }
4981da177e4SLinus Torvalds #endif
49905e792e3SEric W. Biederman arm_notify_die("Oops - undefined instruction", regs,
50005e792e3SEric W. Biederman SIGILL, ILL_ILLOPC, pc, 0, 6);
5011da177e4SLinus Torvalds }
NOKPROBE_SYMBOL(do_undefinstr)502eb0146daSMasami Hiramatsu NOKPROBE_SYMBOL(do_undefinstr)
5031da177e4SLinus Torvalds
5041da177e4SLinus Torvalds /*
505c0e7f7eeSDaniel Thompson * Handle FIQ similarly to NMI on x86 systems.
506c0e7f7eeSDaniel Thompson *
507c0e7f7eeSDaniel Thompson * The runtime environment for NMIs is extremely restrictive
508c0e7f7eeSDaniel Thompson * (NMIs can pre-empt critical sections meaning almost all locking is
509c0e7f7eeSDaniel Thompson * forbidden) meaning this default FIQ handling must only be used in
510c0e7f7eeSDaniel Thompson * circumstances where non-maskability improves robustness, such as
511c0e7f7eeSDaniel Thompson * watchdog or debug logic.
512c0e7f7eeSDaniel Thompson *
513c0e7f7eeSDaniel Thompson * This handler is not appropriate for general purpose use in drivers
514c0e7f7eeSDaniel Thompson * platform code and can be overrideen using set_fiq_handler.
515c0e7f7eeSDaniel Thompson */
516c0e7f7eeSDaniel Thompson asmlinkage void __exception_irq_entry handle_fiq_as_nmi(struct pt_regs *regs)
517c0e7f7eeSDaniel Thompson {
518c0e7f7eeSDaniel Thompson struct pt_regs *old_regs = set_irq_regs(regs);
519c0e7f7eeSDaniel Thompson
520c0e7f7eeSDaniel Thompson nmi_enter();
521c0e7f7eeSDaniel Thompson
522c0e7f7eeSDaniel Thompson /* nop. FIQ handlers for special arch/arm features can be added here. */
523c0e7f7eeSDaniel Thompson
524c0e7f7eeSDaniel Thompson nmi_exit();
525c0e7f7eeSDaniel Thompson
526c0e7f7eeSDaniel Thompson set_irq_regs(old_regs);
527c0e7f7eeSDaniel Thompson }
528c0e7f7eeSDaniel Thompson
529c0e7f7eeSDaniel Thompson /*
5301da177e4SLinus Torvalds * bad_mode handles the impossible case in the vectors. If you see one of
5311da177e4SLinus Torvalds * these, then it's extremely serious, and could mean you have buggy hardware.
5321da177e4SLinus Torvalds * It never returns, and never tries to sync. We hope that we can at least
5331da177e4SLinus Torvalds * dump out some state information...
5341da177e4SLinus Torvalds */
bad_mode(struct pt_regs * regs,int reason)535ae0a846eSRussell King asmlinkage void bad_mode(struct pt_regs *regs, int reason)
5361da177e4SLinus Torvalds {
5371da177e4SLinus Torvalds console_verbose();
5381da177e4SLinus Torvalds
5394ed89f22SRussell King pr_crit("Bad mode in %s handler detected\n", handler[reason]);
5401da177e4SLinus Torvalds
5411da177e4SLinus Torvalds die("Oops - bad mode", regs, 0);
5421da177e4SLinus Torvalds local_irq_disable();
5431da177e4SLinus Torvalds panic("bad mode");
5441da177e4SLinus Torvalds }
5451da177e4SLinus Torvalds
bad_syscall(int n,struct pt_regs * regs)5461da177e4SLinus Torvalds static int bad_syscall(int n, struct pt_regs *regs)
5471da177e4SLinus Torvalds {
548a4980448SRichard Weinberger if ((current->personality & PER_MASK) != PER_LINUX) {
549a4980448SRichard Weinberger send_sig(SIGSEGV, current, 1);
5501da177e4SLinus Torvalds return regs->ARM_r0;
5511da177e4SLinus Torvalds }
5521da177e4SLinus Torvalds
5531da177e4SLinus Torvalds #ifdef CONFIG_DEBUG_USER
5541da177e4SLinus Torvalds if (user_debug & UDBG_SYSCALL) {
5554ed89f22SRussell King pr_err("[%d] %s: obsolete system call %08x.\n",
55619c5870cSAlexey Dobriyan task_pid_nr(current), current->comm, n);
557e40c2ec6SRussell King dump_instr(KERN_ERR, regs);
5581da177e4SLinus Torvalds }
5591da177e4SLinus Torvalds #endif
5601da177e4SLinus Torvalds
56105e792e3SEric W. Biederman arm_notify_die("Oops - bad syscall", regs, SIGILL, ILL_ILLTRP,
56205e792e3SEric W. Biederman (void __user *)instruction_pointer(regs) -
56305e792e3SEric W. Biederman (thumb_mode(regs) ? 2 : 4),
56405e792e3SEric W. Biederman n, 0);
5651da177e4SLinus Torvalds
5661da177e4SLinus Torvalds return regs->ARM_r0;
5671da177e4SLinus Torvalds }
5681da177e4SLinus Torvalds
56928256d61SWill Deacon static inline int
__do_cache_op(unsigned long start,unsigned long end)57028256d61SWill Deacon __do_cache_op(unsigned long start, unsigned long end)
57128256d61SWill Deacon {
57228256d61SWill Deacon int ret;
57328256d61SWill Deacon
57428256d61SWill Deacon do {
575b31459adSJon Medhurst unsigned long chunk = min(PAGE_SIZE, end - start);
576b31459adSJon Medhurst
5773f4aa45cSVladimir Murzin if (fatal_signal_pending(current))
5783f4aa45cSVladimir Murzin return 0;
57928256d61SWill Deacon
580fca7f8e6SChristoph Hellwig ret = flush_icache_user_range(start, start + chunk);
58128256d61SWill Deacon if (ret)
58228256d61SWill Deacon return ret;
58328256d61SWill Deacon
58428256d61SWill Deacon cond_resched();
58528256d61SWill Deacon start += chunk;
58628256d61SWill Deacon } while (start < end);
58728256d61SWill Deacon
58828256d61SWill Deacon return 0;
58928256d61SWill Deacon }
59028256d61SWill Deacon
591c5102f59SWill Deacon static inline int
do_cache_op(unsigned long start,unsigned long end,int flags)5921da177e4SLinus Torvalds do_cache_op(unsigned long start, unsigned long end, int flags)
5931da177e4SLinus Torvalds {
5941da177e4SLinus Torvalds if (end < start || flags)
595c5102f59SWill Deacon return -EINVAL;
5961da177e4SLinus Torvalds
59723fc539eSArnd Bergmann if (!access_ok((void __user *)start, end - start))
59897c72d89SWill Deacon return -EFAULT;
5991da177e4SLinus Torvalds
60028256d61SWill Deacon return __do_cache_op(start, end);
6011da177e4SLinus Torvalds }
6021da177e4SLinus Torvalds
6031da177e4SLinus Torvalds /*
6041da177e4SLinus Torvalds * Handle all unrecognised system calls.
6051da177e4SLinus Torvalds * 0x9f0000 - 0x9fffff are some more esoteric system calls
6061da177e4SLinus Torvalds */
6071da177e4SLinus Torvalds #define NR(x) ((__ARM_NR_##x) - __ARM_NR_BASE)
arm_syscall(int no,struct pt_regs * regs)6081da177e4SLinus Torvalds asmlinkage int arm_syscall(int no, struct pt_regs *regs)
6091da177e4SLinus Torvalds {
6103f2829a3SNicolas Pitre if ((no >> 16) != (__ARM_NR_BASE>> 16))
6111da177e4SLinus Torvalds return bad_syscall(no, regs);
6121da177e4SLinus Torvalds
6131da177e4SLinus Torvalds switch (no & 0xffff) {
6141da177e4SLinus Torvalds case 0: /* branch through 0 */
61505e792e3SEric W. Biederman arm_notify_die("branch through zero", regs,
61605e792e3SEric W. Biederman SIGSEGV, SEGV_MAPERR, NULL, 0, 0);
6171da177e4SLinus Torvalds return 0;
6181da177e4SLinus Torvalds
6191da177e4SLinus Torvalds case NR(breakpoint): /* SWI BREAK_POINT */
6201da177e4SLinus Torvalds regs->ARM_pc -= thumb_mode(regs) ? 2 : 4;
621e9a06509SEric W. Biederman ptrace_break(regs);
6221da177e4SLinus Torvalds return regs->ARM_r0;
6231da177e4SLinus Torvalds
6241da177e4SLinus Torvalds /*
6251da177e4SLinus Torvalds * Flush a region from virtual address 'r0' to virtual address 'r1'
6261da177e4SLinus Torvalds * _exclusive_. There is no alignment requirement on either address;
6271da177e4SLinus Torvalds * user space does not need to know the hardware cache layout.
6281da177e4SLinus Torvalds *
6291da177e4SLinus Torvalds * r2 contains flags. It should ALWAYS be passed as ZERO until it
6301da177e4SLinus Torvalds * is defined to be something else. For now we ignore it, but may
6311da177e4SLinus Torvalds * the fires of hell burn in your belly if you break this rule. ;)
6321da177e4SLinus Torvalds *
6331da177e4SLinus Torvalds * (at a later date, we may want to allow this call to not flush
6341da177e4SLinus Torvalds * various aspects of the cache. Passing '0' will guarantee that
6351da177e4SLinus Torvalds * everything necessary gets flushed to maintain consistency in
6361da177e4SLinus Torvalds * the specified region).
6371da177e4SLinus Torvalds */
6381da177e4SLinus Torvalds case NR(cacheflush):
639c5102f59SWill Deacon return do_cache_op(regs->ARM_r0, regs->ARM_r1, regs->ARM_r2);
6401da177e4SLinus Torvalds
6411da177e4SLinus Torvalds case NR(usr26):
6421da177e4SLinus Torvalds if (!(elf_hwcap & HWCAP_26BIT))
6431da177e4SLinus Torvalds break;
6441da177e4SLinus Torvalds regs->ARM_cpsr &= ~MODE32_BIT;
6451da177e4SLinus Torvalds return regs->ARM_r0;
6461da177e4SLinus Torvalds
6471da177e4SLinus Torvalds case NR(usr32):
6481da177e4SLinus Torvalds if (!(elf_hwcap & HWCAP_26BIT))
6491da177e4SLinus Torvalds break;
6501da177e4SLinus Torvalds regs->ARM_cpsr |= MODE32_BIT;
6511da177e4SLinus Torvalds return regs->ARM_r0;
6521da177e4SLinus Torvalds
6531da177e4SLinus Torvalds case NR(set_tls):
654fbfb872fSNathan Lynch set_tls(regs->ARM_r0);
6551da177e4SLinus Torvalds return 0;
6561da177e4SLinus Torvalds
6578fcd6c45SNicolas Pitre case NR(get_tls):
6588fcd6c45SNicolas Pitre return current_thread_info()->tp_value[0];
6598fcd6c45SNicolas Pitre
6601da177e4SLinus Torvalds default:
6611da177e4SLinus Torvalds /* Calls 9f00xx..9f07ff are defined to return -ENOSYS
6621da177e4SLinus Torvalds if not implemented, rather than raising SIGILL. This
6631da177e4SLinus Torvalds way the calling program can gracefully determine whether
6641da177e4SLinus Torvalds a feature is supported. */
665bfd2e29fSRussell King if ((no & 0xffff) <= 0x7ff)
6661da177e4SLinus Torvalds return -ENOSYS;
6671da177e4SLinus Torvalds break;
6681da177e4SLinus Torvalds }
6691da177e4SLinus Torvalds #ifdef CONFIG_DEBUG_USER
6701da177e4SLinus Torvalds /*
6711da177e4SLinus Torvalds * experience shows that these seem to indicate that
6721da177e4SLinus Torvalds * something catastrophic has happened
6731da177e4SLinus Torvalds */
6741da177e4SLinus Torvalds if (user_debug & UDBG_SYSCALL) {
6754ed89f22SRussell King pr_err("[%d] %s: arm syscall %d\n",
67619c5870cSAlexey Dobriyan task_pid_nr(current), current->comm, no);
677e8d7b735SDmitry Safonov dump_instr(KERN_ERR, regs);
6781da177e4SLinus Torvalds if (user_mode(regs)) {
679652a12efSRussell King __show_regs(regs);
680e8d7b735SDmitry Safonov c_backtrace(frame_pointer(regs), processor_mode(regs), KERN_ERR);
6811da177e4SLinus Torvalds }
6821da177e4SLinus Torvalds }
6831da177e4SLinus Torvalds #endif
68405e792e3SEric W. Biederman arm_notify_die("Oops - bad syscall(2)", regs, SIGILL, ILL_ILLTRP,
68505e792e3SEric W. Biederman (void __user *)instruction_pointer(regs) -
68605e792e3SEric W. Biederman (thumb_mode(regs) ? 2 : 4),
68705e792e3SEric W. Biederman no, 0);
6881da177e4SLinus Torvalds return 0;
6891da177e4SLinus Torvalds }
6901da177e4SLinus Torvalds
6914b0e07a5SNicolas Pitre #ifdef CONFIG_TLS_REG_EMUL
6922d2669b6SNicolas Pitre
6932d2669b6SNicolas Pitre /*
6942d2669b6SNicolas Pitre * We might be running on an ARMv6+ processor which should have the TLS
6954b0e07a5SNicolas Pitre * register but for some reason we can't use it, or maybe an SMP system
6964b0e07a5SNicolas Pitre * using a pre-ARMv6 processor (there are apparently a few prototypes like
6974b0e07a5SNicolas Pitre * that in existence) and therefore access to that register must be
6984b0e07a5SNicolas Pitre * emulated.
6992d2669b6SNicolas Pitre */
7002d2669b6SNicolas Pitre
get_tp_trap(struct pt_regs * regs,unsigned int instr)7012d2669b6SNicolas Pitre static int get_tp_trap(struct pt_regs *regs, unsigned int instr)
7022d2669b6SNicolas Pitre {
7032d2669b6SNicolas Pitre int reg = (instr >> 12) & 15;
7042d2669b6SNicolas Pitre if (reg == 15)
7052d2669b6SNicolas Pitre return 1;
706a4780adeSAndré Hentschel regs->uregs[reg] = current_thread_info()->tp_value[0];
7072d2669b6SNicolas Pitre regs->ARM_pc += 4;
7082d2669b6SNicolas Pitre return 0;
7092d2669b6SNicolas Pitre }
7102d2669b6SNicolas Pitre
7112d2669b6SNicolas Pitre static struct undef_hook arm_mrc_hook = {
7122d2669b6SNicolas Pitre .instr_mask = 0x0fff0fff,
7132d2669b6SNicolas Pitre .instr_val = 0x0e1d0f70,
7142d2669b6SNicolas Pitre .cpsr_mask = PSR_T_BIT,
7152d2669b6SNicolas Pitre .cpsr_val = 0,
7162d2669b6SNicolas Pitre .fn = get_tp_trap,
7172d2669b6SNicolas Pitre };
7182d2669b6SNicolas Pitre
arm_mrc_hook_init(void)7192d2669b6SNicolas Pitre static int __init arm_mrc_hook_init(void)
7202d2669b6SNicolas Pitre {
7212d2669b6SNicolas Pitre register_undef_hook(&arm_mrc_hook);
7222d2669b6SNicolas Pitre return 0;
7232d2669b6SNicolas Pitre }
7242d2669b6SNicolas Pitre
7252d2669b6SNicolas Pitre late_initcall(arm_mrc_hook_init);
7262d2669b6SNicolas Pitre
7272d2669b6SNicolas Pitre #endif
7282d2669b6SNicolas Pitre
7291da177e4SLinus Torvalds /*
7301da177e4SLinus Torvalds * A data abort trap was taken, but we did not handle the instruction.
7311da177e4SLinus Torvalds * Try to abort the user program, or panic if it was the kernel.
7321da177e4SLinus Torvalds */
7331da177e4SLinus Torvalds asmlinkage void
baddataabort(int code,unsigned long instr,struct pt_regs * regs)7341da177e4SLinus Torvalds baddataabort(int code, unsigned long instr, struct pt_regs *regs)
7351da177e4SLinus Torvalds {
7361da177e4SLinus Torvalds unsigned long addr = instruction_pointer(regs);
7373eb0f519SEric W. Biederman
7381da177e4SLinus Torvalds #ifdef CONFIG_DEBUG_USER
7391da177e4SLinus Torvalds if (user_debug & UDBG_BADABORT) {
740bafeb7a0SRussell King pr_err("8<--- cut here ---\n");
7414ed89f22SRussell King pr_err("[%d] %s: bad data abort: code %d instr 0x%08lx\n",
74219c5870cSAlexey Dobriyan task_pid_nr(current), current->comm, code, instr);
743e40c2ec6SRussell King dump_instr(KERN_ERR, regs);
74449b38c34SRussell King show_pte(KERN_ERR, current->mm, addr);
7451da177e4SLinus Torvalds }
7461da177e4SLinus Torvalds #endif
7471da177e4SLinus Torvalds
74805e792e3SEric W. Biederman arm_notify_die("unknown data abort code", regs,
74905e792e3SEric W. Biederman SIGILL, ILL_ILLOPC, (void __user *)addr, instr, 0);
7501da177e4SLinus Torvalds }
7511da177e4SLinus Torvalds
__readwrite_bug(const char * fn)7521da177e4SLinus Torvalds void __readwrite_bug(const char *fn)
7531da177e4SLinus Torvalds {
7544ed89f22SRussell King pr_err("%s called, but not implemented\n", fn);
7551da177e4SLinus Torvalds BUG();
7561da177e4SLinus Torvalds }
7571da177e4SLinus Torvalds EXPORT_SYMBOL(__readwrite_bug);
7581da177e4SLinus Torvalds
759*4b026ca3SArnd Bergmann #ifdef CONFIG_MMU
__pte_error(const char * file,int line,pte_t pte)76069529c0eSRussell King void __pte_error(const char *file, int line, pte_t pte)
7611da177e4SLinus Torvalds {
7624ed89f22SRussell King pr_err("%s:%d: bad pte %08llx.\n", file, line, (long long)pte_val(pte));
7631da177e4SLinus Torvalds }
7641da177e4SLinus Torvalds
__pmd_error(const char * file,int line,pmd_t pmd)76569529c0eSRussell King void __pmd_error(const char *file, int line, pmd_t pmd)
7661da177e4SLinus Torvalds {
7674ed89f22SRussell King pr_err("%s:%d: bad pmd %08llx.\n", file, line, (long long)pmd_val(pmd));
7681da177e4SLinus Torvalds }
7691da177e4SLinus Torvalds
__pgd_error(const char * file,int line,pgd_t pgd)77069529c0eSRussell King void __pgd_error(const char *file, int line, pgd_t pgd)
7711da177e4SLinus Torvalds {
7724ed89f22SRussell King pr_err("%s:%d: bad pgd %08llx.\n", file, line, (long long)pgd_val(pgd));
7731da177e4SLinus Torvalds }
774*4b026ca3SArnd Bergmann #endif
7751da177e4SLinus Torvalds
__div0(void)7761da177e4SLinus Torvalds asmlinkage void __div0(void)
7771da177e4SLinus Torvalds {
7784ed89f22SRussell King pr_err("Division by zero in kernel.\n");
7791da177e4SLinus Torvalds dump_stack();
7801da177e4SLinus Torvalds }
7811da177e4SLinus Torvalds EXPORT_SYMBOL(__div0);
7821da177e4SLinus Torvalds
abort(void)7831da177e4SLinus Torvalds void abort(void)
7841da177e4SLinus Torvalds {
7851da177e4SLinus Torvalds BUG();
7861da177e4SLinus Torvalds
7871da177e4SLinus Torvalds /* if that doesn't kill us, halt */
7881da177e4SLinus Torvalds panic("Oops failed to kill thread");
7891da177e4SLinus Torvalds }
7901da177e4SLinus Torvalds
791f6f91b0dSRussell King #ifdef CONFIG_KUSER_HELPERS
kuser_init(void * vectors)792f6f91b0dSRussell King static void __init kuser_init(void *vectors)
793f159f4edSTony Lindgren {
794f6f91b0dSRussell King extern char __kuser_helper_start[], __kuser_helper_end[];
795f6f91b0dSRussell King int kuser_sz = __kuser_helper_end - __kuser_helper_start;
796f6f91b0dSRussell King
797f6f91b0dSRussell King memcpy(vectors + 0x1000 - kuser_sz, __kuser_helper_start, kuser_sz);
798f6f91b0dSRussell King
799f159f4edSTony Lindgren /*
800f159f4edSTony Lindgren * vectors + 0xfe0 = __kuser_get_tls
801f159f4edSTony Lindgren * vectors + 0xfe8 = hardware TLS instruction at 0xffff0fe8
802f159f4edSTony Lindgren */
803f159f4edSTony Lindgren if (tls_emu || has_tls_reg)
804f6f91b0dSRussell King memcpy(vectors + 0xfe0, vectors + 0xfe8, 4);
805f159f4edSTony Lindgren }
806f6f91b0dSRussell King #else
kuser_init(void * vectors)8075761704aSOlof Johansson static inline void __init kuser_init(void *vectors)
808f6f91b0dSRussell King {
809f6f91b0dSRussell King }
810f6f91b0dSRussell King #endif
811f159f4edSTony Lindgren
81204e91b73SRussell King (Oracle) #ifndef CONFIG_CPU_V7M
copy_from_lma(void * vma,void * lma_start,void * lma_end)81304e91b73SRussell King (Oracle) static void copy_from_lma(void *vma, void *lma_start, void *lma_end)
81404e91b73SRussell King (Oracle) {
81504e91b73SRussell King (Oracle) memcpy(vma, lma_start, lma_end - lma_start);
81604e91b73SRussell King (Oracle) }
81704e91b73SRussell King (Oracle)
flush_vectors(void * vma,size_t offset,size_t size)81804e91b73SRussell King (Oracle) static void flush_vectors(void *vma, size_t offset, size_t size)
81904e91b73SRussell King (Oracle) {
82004e91b73SRussell King (Oracle) unsigned long start = (unsigned long)vma + offset;
82104e91b73SRussell King (Oracle) unsigned long end = start + size;
82204e91b73SRussell King (Oracle)
82304e91b73SRussell King (Oracle) flush_icache_range(start, end);
82404e91b73SRussell King (Oracle) }
82504e91b73SRussell King (Oracle)
826b9baf5c8SRussell King (Oracle) #ifdef CONFIG_HARDEN_BRANCH_HISTORY
spectre_bhb_update_vectors(unsigned int method)827b9baf5c8SRussell King (Oracle) int spectre_bhb_update_vectors(unsigned int method)
828b9baf5c8SRussell King (Oracle) {
829b9baf5c8SRussell King (Oracle) extern char __vectors_bhb_bpiall_start[], __vectors_bhb_bpiall_end[];
830b9baf5c8SRussell King (Oracle) extern char __vectors_bhb_loop8_start[], __vectors_bhb_loop8_end[];
831b9baf5c8SRussell King (Oracle) void *vec_start, *vec_end;
832b9baf5c8SRussell King (Oracle)
833b9baf5c8SRussell King (Oracle) if (system_state >= SYSTEM_FREEING_INITMEM) {
834b9baf5c8SRussell King (Oracle) pr_err("CPU%u: Spectre BHB workaround too late - system vulnerable\n",
835b9baf5c8SRussell King (Oracle) smp_processor_id());
836b9baf5c8SRussell King (Oracle) return SPECTRE_VULNERABLE;
837b9baf5c8SRussell King (Oracle) }
838b9baf5c8SRussell King (Oracle)
839b9baf5c8SRussell King (Oracle) switch (method) {
840b9baf5c8SRussell King (Oracle) case SPECTRE_V2_METHOD_LOOP8:
841b9baf5c8SRussell King (Oracle) vec_start = __vectors_bhb_loop8_start;
842b9baf5c8SRussell King (Oracle) vec_end = __vectors_bhb_loop8_end;
843b9baf5c8SRussell King (Oracle) break;
844b9baf5c8SRussell King (Oracle)
845b9baf5c8SRussell King (Oracle) case SPECTRE_V2_METHOD_BPIALL:
846b9baf5c8SRussell King (Oracle) vec_start = __vectors_bhb_bpiall_start;
847b9baf5c8SRussell King (Oracle) vec_end = __vectors_bhb_bpiall_end;
848b9baf5c8SRussell King (Oracle) break;
849b9baf5c8SRussell King (Oracle)
850b9baf5c8SRussell King (Oracle) default:
851b9baf5c8SRussell King (Oracle) pr_err("CPU%u: unknown Spectre BHB state %d\n",
852b9baf5c8SRussell King (Oracle) smp_processor_id(), method);
853b9baf5c8SRussell King (Oracle) return SPECTRE_VULNERABLE;
854b9baf5c8SRussell King (Oracle) }
855b9baf5c8SRussell King (Oracle)
856b9baf5c8SRussell King (Oracle) copy_from_lma(vectors_page, vec_start, vec_end);
857b9baf5c8SRussell King (Oracle) flush_vectors(vectors_page, 0, vec_end - vec_start);
858b9baf5c8SRussell King (Oracle)
859b9baf5c8SRussell King (Oracle) return SPECTRE_MITIGATED;
860b9baf5c8SRussell King (Oracle) }
861b9baf5c8SRussell King (Oracle) #endif
862b9baf5c8SRussell King (Oracle)
early_trap_init(void * vectors_base)86394e5a85bSRussell King void __init early_trap_init(void *vectors_base)
8645cbad0ebSJason Wessel {
8657933523dSRussell King extern char __stubs_start[], __stubs_end[];
8667933523dSRussell King extern char __vectors_start[], __vectors_end[];
867f928d4f2SRussell King unsigned i;
8681da177e4SLinus Torvalds
86994e5a85bSRussell King vectors_page = vectors_base;
87094e5a85bSRussell King
8717933523dSRussell King /*
872f928d4f2SRussell King * Poison the vectors page with an undefined instruction. This
873f928d4f2SRussell King * instruction is chosen to be undefined for both ARM and Thumb
874f928d4f2SRussell King * ISAs. The Thumb version is an undefined instruction with a
875f928d4f2SRussell King * branch back to the undefined instruction.
876f928d4f2SRussell King */
877f928d4f2SRussell King for (i = 0; i < PAGE_SIZE / sizeof(u32); i++)
878f928d4f2SRussell King ((u32 *)vectors_base)[i] = 0xe7fddef1;
879f928d4f2SRussell King
880f928d4f2SRussell King /*
8812d2669b6SNicolas Pitre * Copy the vectors, stubs and kuser helpers (in entry-armv.S)
8822d2669b6SNicolas Pitre * into the vector page, mapped at 0xffff0000, and ensure these
8832d2669b6SNicolas Pitre * are visible to the instruction stream.
8847933523dSRussell King */
88504e91b73SRussell King (Oracle) copy_from_lma(vectors_base, __vectors_start, __vectors_end);
88604e91b73SRussell King (Oracle) copy_from_lma(vectors_base + 0x1000, __stubs_start, __stubs_end);
887e00d349eSRussell King
888f6f91b0dSRussell King kuser_init(vectors_base);
889f159f4edSTony Lindgren
89004e91b73SRussell King (Oracle) flush_vectors(vectors_base, 0, PAGE_SIZE * 2);
89104e91b73SRussell King (Oracle) }
89255bdd694SCatalin Marinas #else /* ifndef CONFIG_CPU_V7M */
early_trap_init(void * vectors_base)89304e91b73SRussell King (Oracle) void __init early_trap_init(void *vectors_base)
89404e91b73SRussell King (Oracle) {
89555bdd694SCatalin Marinas /*
89655bdd694SCatalin Marinas * on V7-M there is no need to copy the vector table to a dedicated
89755bdd694SCatalin Marinas * memory area. The address is configurable and so a table in the kernel
89855bdd694SCatalin Marinas * image can be used.
89955bdd694SCatalin Marinas */
9001da177e4SLinus Torvalds }
90104e91b73SRussell King (Oracle) #endif
902a1c510d0SArd Biesheuvel
903a1c510d0SArd Biesheuvel #ifdef CONFIG_VMAP_STACK
904a1c510d0SArd Biesheuvel
905a1c510d0SArd Biesheuvel DECLARE_PER_CPU(u8 *, irq_stack_ptr);
906a1c510d0SArd Biesheuvel
907a1c510d0SArd Biesheuvel asmlinkage DEFINE_PER_CPU(u8 *, overflow_stack_ptr);
908a1c510d0SArd Biesheuvel
allocate_overflow_stacks(void)909a1c510d0SArd Biesheuvel static int __init allocate_overflow_stacks(void)
910a1c510d0SArd Biesheuvel {
911a1c510d0SArd Biesheuvel u8 *stack;
912a1c510d0SArd Biesheuvel int cpu;
913a1c510d0SArd Biesheuvel
914a1c510d0SArd Biesheuvel for_each_possible_cpu(cpu) {
915a1c510d0SArd Biesheuvel stack = (u8 *)__get_free_page(GFP_KERNEL);
916a1c510d0SArd Biesheuvel if (WARN_ON(!stack))
917a1c510d0SArd Biesheuvel return -ENOMEM;
918a1c510d0SArd Biesheuvel per_cpu(overflow_stack_ptr, cpu) = &stack[OVERFLOW_STACK_SIZE];
919a1c510d0SArd Biesheuvel }
920a1c510d0SArd Biesheuvel return 0;
921a1c510d0SArd Biesheuvel }
922a1c510d0SArd Biesheuvel early_initcall(allocate_overflow_stacks);
923a1c510d0SArd Biesheuvel
handle_bad_stack(struct pt_regs * regs)924a1c510d0SArd Biesheuvel asmlinkage void handle_bad_stack(struct pt_regs *regs)
925a1c510d0SArd Biesheuvel {
926a1c510d0SArd Biesheuvel unsigned long tsk_stk = (unsigned long)current->stack;
9279c46929eSArd Biesheuvel #ifdef CONFIG_IRQSTACKS
928370d51c8SZhen Lei unsigned long irq_stk = (unsigned long)raw_cpu_read(irq_stack_ptr);
9299c46929eSArd Biesheuvel #endif
930370d51c8SZhen Lei unsigned long ovf_stk = (unsigned long)raw_cpu_read(overflow_stack_ptr);
931a1c510d0SArd Biesheuvel
932a1c510d0SArd Biesheuvel console_verbose();
933a1c510d0SArd Biesheuvel pr_emerg("Insufficient stack space to handle exception!");
934a1c510d0SArd Biesheuvel
935a1c510d0SArd Biesheuvel pr_emerg("Task stack: [0x%08lx..0x%08lx]\n",
936a1c510d0SArd Biesheuvel tsk_stk, tsk_stk + THREAD_SIZE);
9379c46929eSArd Biesheuvel #ifdef CONFIG_IRQSTACKS
938a1c510d0SArd Biesheuvel pr_emerg("IRQ stack: [0x%08lx..0x%08lx]\n",
939a1c510d0SArd Biesheuvel irq_stk - THREAD_SIZE, irq_stk);
9409c46929eSArd Biesheuvel #endif
941a1c510d0SArd Biesheuvel pr_emerg("Overflow stack: [0x%08lx..0x%08lx]\n",
942a1c510d0SArd Biesheuvel ovf_stk - OVERFLOW_STACK_SIZE, ovf_stk);
943a1c510d0SArd Biesheuvel
944a1c510d0SArd Biesheuvel die("kernel stack overflow", regs, 0);
945a1c510d0SArd Biesheuvel }
946a1c510d0SArd Biesheuvel
947d31e23afSArd Biesheuvel #ifndef CONFIG_ARM_LPAE
948a1c510d0SArd Biesheuvel /*
949a1c510d0SArd Biesheuvel * Normally, we rely on the logic in do_translation_fault() to update stale PMD
950a1c510d0SArd Biesheuvel * entries covering the vmalloc space in a task's page tables when it first
951a1c510d0SArd Biesheuvel * accesses the region in question. Unfortunately, this is not sufficient when
952a1c510d0SArd Biesheuvel * the task stack resides in the vmalloc region, as do_translation_fault() is a
953a1c510d0SArd Biesheuvel * C function that needs a stack to run.
954a1c510d0SArd Biesheuvel *
955a1c510d0SArd Biesheuvel * So we need to ensure that these PMD entries are up to date *before* the MM
956a1c510d0SArd Biesheuvel * switch. As we already have some logic in the MM switch path that takes care
957a1c510d0SArd Biesheuvel * of this, let's trigger it by bumping the counter every time the core vmalloc
958d31e23afSArd Biesheuvel * code modifies a PMD entry in the vmalloc region. Use release semantics on
959d31e23afSArd Biesheuvel * the store so that other CPUs observing the counter's new value are
960d31e23afSArd Biesheuvel * guaranteed to see the updated page table entries as well.
961a1c510d0SArd Biesheuvel */
arch_sync_kernel_mappings(unsigned long start,unsigned long end)962a1c510d0SArd Biesheuvel void arch_sync_kernel_mappings(unsigned long start, unsigned long end)
963a1c510d0SArd Biesheuvel {
964d31e23afSArd Biesheuvel if (start < VMALLOC_END && end > VMALLOC_START)
965d31e23afSArd Biesheuvel atomic_inc_return_release(&init_mm.context.vmalloc_seq);
966a1c510d0SArd Biesheuvel }
967d31e23afSArd Biesheuvel #endif
968a1c510d0SArd Biesheuvel #endif
969