LCOV - code coverage report
Current view: top level - arch/arm/kernel - traps.c (source / functions) Hit Total Coverage
Test: Real Lines: 89 250 35.6 %
Date: 2020-10-17 15:46:16 Functions: 0 32 0.0 %
Legend: Neither, QEMU, Real, Both Branches: 0 0 -

           Branch data     Line data    Source code
       1                 :            : // SPDX-License-Identifier: GPL-2.0-only
       2                 :            : /*
       3                 :            :  *  linux/arch/arm/kernel/traps.c
       4                 :            :  *
       5                 :            :  *  Copyright (C) 1995-2009 Russell King
       6                 :            :  *  Fragments that appear the same as linux/arch/i386/kernel/traps.c (C) Linus Torvalds
       7                 :            :  *
       8                 :            :  *  'traps.c' handles hardware exceptions after we have saved some state in
       9                 :            :  *  'linux/arch/arm/lib/traps.S'.  Mostly a debugging aid, but will probably
      10                 :            :  *  kill the offending process.
      11                 :            :  */
      12                 :            : #include <linux/signal.h>
      13                 :            : #include <linux/personality.h>
      14                 :            : #include <linux/kallsyms.h>
      15                 :            : #include <linux/spinlock.h>
      16                 :            : #include <linux/uaccess.h>
      17                 :            : #include <linux/hardirq.h>
      18                 :            : #include <linux/kdebug.h>
      19                 :            : #include <linux/kprobes.h>
      20                 :            : #include <linux/module.h>
      21                 :            : #include <linux/kexec.h>
      22                 :            : #include <linux/bug.h>
      23                 :            : #include <linux/delay.h>
      24                 :            : #include <linux/init.h>
      25                 :            : #include <linux/sched/signal.h>
      26                 :            : #include <linux/sched/debug.h>
      27                 :            : #include <linux/sched/task_stack.h>
      28                 :            : #include <linux/irq.h>
      29                 :            : 
      30                 :            : #include <linux/atomic.h>
      31                 :            : #include <asm/cacheflush.h>
      32                 :            : #include <asm/exception.h>
      33                 :            : #include <asm/unistd.h>
      34                 :            : #include <asm/traps.h>
      35                 :            : #include <asm/ptrace.h>
      36                 :            : #include <asm/unwind.h>
      37                 :            : #include <asm/tls.h>
      38                 :            : #include <asm/system_misc.h>
      39                 :            : #include <asm/opcodes.h>
      40                 :            : 
      41                 :            : 
      42                 :            : static const char *handler[]= {
      43                 :            :         "prefetch abort",
      44                 :            :         "data abort",
      45                 :            :         "address exception",
      46                 :            :         "interrupt",
      47                 :            :         "undefined instruction",
      48                 :            : };
      49                 :            : 
      50                 :            : void *vectors_page;
      51                 :            : 
      52                 :            : #ifdef CONFIG_DEBUG_USER
      53                 :            : unsigned int user_debug;
      54                 :            : 
      55                 :            : static int __init user_debug_setup(char *str)
      56                 :            : {
      57                 :            :         get_option(&str, &user_debug);
      58                 :            :         return 1;
      59                 :            : }
      60                 :            : __setup("user_debug=", user_debug_setup);
      61                 :            : #endif
      62                 :            : 
      63                 :            : static void dump_mem(const char *, const char *, unsigned long, unsigned long);
      64                 :            : 
      65                 :          1 : void dump_backtrace_entry(unsigned long where, unsigned long from, unsigned long frame)
      66                 :            : {
      67                 :            : #ifdef CONFIG_KALLSYMS
      68                 :          1 :         printk("[<%08lx>] (%ps) from [<%08lx>] (%pS)\n", where, (void *)where, from, (void *)from);
      69                 :            : #else
      70                 :            :         printk("Function entered at [<%08lx>] from [<%08lx>]\n", where, from);
      71                 :            : #endif
      72                 :            : 
      73                 :          1 :         if (in_entry_text(from))
      74                 :          1 :                 dump_mem("", "Exception stack", frame + 4, frame + 4 + sizeof(struct pt_regs));
      75                 :          1 : }
      76                 :            : 
      77                 :          1 : void dump_backtrace_stm(u32 *stack, u32 instruction)
      78                 :            : {
      79                 :            :         char str[80], *p;
      80                 :            :         unsigned int x;
      81                 :            :         int reg;
      82                 :            : 
      83                 :          1 :         for (reg = 10, x = 0, p = str; reg >= 0; reg--) {
      84                 :          1 :                 if (instruction & BIT(reg)) {
      85                 :          1 :                         p += sprintf(p, " r%d:%08x", reg, *stack--);
      86                 :          1 :                         if (++x == 6) {
      87                 :            :                                 x = 0;
      88                 :            :                                 p = str;
      89                 :          1 :                                 printk("%s\n", str);
      90                 :            :                         }
      91                 :            :                 }
      92                 :            :         }
      93                 :          1 :         if (p != str)
      94                 :          1 :                 printk("%s\n", str);
      95                 :          1 : }
      96                 :            : 
      97                 :            : #ifndef CONFIG_ARM_UNWIND
      98                 :            : /*
      99                 :            :  * Stack pointers should always be within the kernels view of
     100                 :            :  * physical memory.  If it is not there, then we can't dump
     101                 :            :  * out any information relating to the stack.
     102                 :            :  */
     103                 :            : static int verify_stack(unsigned long sp)
     104                 :            : {
     105                 :          1 :         if (sp < PAGE_OFFSET ||
     106                 :          1 :             (sp > (unsigned long)high_memory && high_memory != NULL))
     107                 :            :                 return -EFAULT;
     108                 :            : 
     109                 :            :         return 0;
     110                 :            : }
     111                 :            : #endif
     112                 :            : 
     113                 :            : /*
     114                 :            :  * Dump out the contents of some memory nicely...
     115                 :            :  */
     116                 :          1 : static void dump_mem(const char *lvl, const char *str, unsigned long bottom,
     117                 :            :                      unsigned long top)
     118                 :            : {
     119                 :            :         unsigned long first;
     120                 :            :         mm_segment_t fs;
     121                 :            :         int i;
     122                 :            : 
     123                 :            :         /*
     124                 :            :          * We need to switch to kernel mode so that we can use __get_user
     125                 :            :          * to safely read from kernel space.  Note that we now dump the
     126                 :            :          * code first, just in case the backtrace kills us.
     127                 :            :          */
     128                 :          1 :         fs = get_fs();
     129                 :            :         set_fs(KERNEL_DS);
     130                 :            : 
     131                 :          1 :         printk("%s%s(0x%08lx to 0x%08lx)\n", lvl, str, bottom, top);
     132                 :            : 
     133                 :          1 :         for (first = bottom & ~31; first < top; first += 32) {
     134                 :            :                 unsigned long p;
     135                 :            :                 char str[sizeof(" 12345678") * 8 + 1];
     136                 :            : 
     137                 :          1 :                 memset(str, ' ', sizeof(str));
     138                 :          1 :                 str[sizeof(str) - 1] = '\0';
     139                 :            : 
     140                 :          1 :                 for (p = first, i = 0; i < 8 && p < top; i++, p += 4) {
     141                 :          1 :                         if (p >= bottom && p < top) {
     142                 :            :                                 unsigned long val;
     143                 :          1 :                                 if (__get_user(val, (unsigned long *)p) == 0)
     144                 :          1 :                                         sprintf(str + i * 9, " %08lx", val);
     145                 :            :                                 else
     146                 :          0 :                                         sprintf(str + i * 9, " ????????");
     147                 :            :                         }
     148                 :            :                 }
     149                 :          1 :                 printk("%s%04lx:%s\n", lvl, first & 0xffff, str);
     150                 :            :         }
     151                 :            : 
     152                 :            :         set_fs(fs);
     153                 :          1 : }
     154                 :            : 
     155                 :          0 : static void __dump_instr(const char *lvl, struct pt_regs *regs)
     156                 :            : {
     157                 :          0 :         unsigned long addr = instruction_pointer(regs);
     158                 :          0 :         const int thumb = thumb_mode(regs);
     159                 :          0 :         const int width = thumb ? 4 : 8;
     160                 :            :         char str[sizeof("00000000 ") * 5 + 2 + 1], *p = str;
     161                 :            :         int i;
     162                 :            : 
     163                 :            :         /*
     164                 :            :          * Note that we now dump the code first, just in case the backtrace
     165                 :            :          * kills us.
     166                 :            :          */
     167                 :            : 
     168                 :          0 :         for (i = -4; i < 1 + !!thumb; i++) {
     169                 :            :                 unsigned int val, bad;
     170                 :            : 
     171                 :          0 :                 if (thumb)
     172                 :          0 :                         bad = get_user(val, &((u16 *)addr)[i]);
     173                 :            :                 else
     174                 :          0 :                         bad = get_user(val, &((u32 *)addr)[i]);
     175                 :            : 
     176                 :          0 :                 if (!bad)
     177                 :          0 :                         p += sprintf(p, i == 0 ? "(%0*x) " : "%0*x ",
     178                 :            :                                         width, val);
     179                 :            :                 else {
     180                 :          0 :                         p += sprintf(p, "bad PC value");
     181                 :          0 :                         break;
     182                 :            :                 }
     183                 :            :         }
     184                 :          0 :         printk("%sCode: %s\n", lvl, str);
     185                 :          0 : }
     186                 :            : 
     187                 :          0 : static void dump_instr(const char *lvl, struct pt_regs *regs)
     188                 :            : {
     189                 :            :         mm_segment_t fs;
     190                 :            : 
     191                 :          0 :         if (!user_mode(regs)) {
     192                 :          0 :                 fs = get_fs();
     193                 :            :                 set_fs(KERNEL_DS);
     194                 :          0 :                 __dump_instr(lvl, regs);
     195                 :            :                 set_fs(fs);
     196                 :            :         } else {
     197                 :          0 :                 __dump_instr(lvl, regs);
     198                 :            :         }
     199                 :          0 : }
     200                 :            : 
     201                 :            : #ifdef CONFIG_ARM_UNWIND
     202                 :            : static inline void dump_backtrace(struct pt_regs *regs, struct task_struct *tsk)
     203                 :            : {
     204                 :            :         unwind_backtrace(regs, tsk);
     205                 :            : }
     206                 :            : #else
     207                 :          1 : static void dump_backtrace(struct pt_regs *regs, struct task_struct *tsk)
     208                 :            : {
     209                 :            :         unsigned int fp, mode;
     210                 :            :         int ok = 1;
     211                 :            : 
     212                 :          1 :         printk("Backtrace: ");
     213                 :            : 
     214                 :          1 :         if (!tsk)
     215                 :          1 :                 tsk = current;
     216                 :            : 
     217                 :          1 :         if (regs) {
     218                 :          0 :                 fp = frame_pointer(regs);
     219                 :          0 :                 mode = processor_mode(regs);
     220                 :          1 :         } else if (tsk != current) {
     221                 :          0 :                 fp = thread_saved_fp(tsk);
     222                 :            :                 mode = 0x10;
     223                 :            :         } else {
     224                 :          1 :                 asm("mov %0, fp" : "=r" (fp) : : "cc");
     225                 :            :                 mode = 0x10;
     226                 :            :         }
     227                 :            : 
     228                 :          1 :         if (!fp) {
     229                 :          0 :                 pr_cont("no frame pointer");
     230                 :            :                 ok = 0;
     231                 :          1 :         } else if (verify_stack(fp)) {
     232                 :          0 :                 pr_cont("invalid frame pointer 0x%08x", fp);
     233                 :            :                 ok = 0;
     234                 :          1 :         } else if (fp < (unsigned long)end_of_stack(tsk))
     235                 :          0 :                 pr_cont("frame pointer underflow");
     236                 :          1 :         pr_cont("\n");
     237                 :            : 
     238                 :          1 :         if (ok)
     239                 :          1 :                 c_backtrace(fp, mode);
     240                 :          1 : }
     241                 :            : #endif
     242                 :            : 
     243                 :          1 : void show_stack(struct task_struct *tsk, unsigned long *sp)
     244                 :            : {
     245                 :          1 :         dump_backtrace(NULL, tsk);
     246                 :          1 :         barrier();
     247                 :          1 : }
     248                 :            : 
     249                 :            : #ifdef CONFIG_PREEMPT
     250                 :            : #define S_PREEMPT " PREEMPT"
     251                 :            : #else
     252                 :            : #define S_PREEMPT ""
     253                 :            : #endif
     254                 :            : #ifdef CONFIG_SMP
     255                 :            : #define S_SMP " SMP"
     256                 :            : #else
     257                 :            : #define S_SMP ""
     258                 :            : #endif
     259                 :            : #ifdef CONFIG_THUMB2_KERNEL
     260                 :            : #define S_ISA " THUMB2"
     261                 :            : #else
     262                 :            : #define S_ISA " ARM"
     263                 :            : #endif
     264                 :            : 
     265                 :          0 : static int __die(const char *str, int err, struct pt_regs *regs)
     266                 :            : {
     267                 :          0 :         struct task_struct *tsk = current;
     268                 :            :         static int die_counter;
     269                 :            :         int ret;
     270                 :            : 
     271                 :          0 :         pr_emerg("Internal error: %s: %x [#%d]" S_PREEMPT S_SMP S_ISA "\n",
     272                 :            :                  str, err, ++die_counter);
     273                 :            : 
     274                 :            :         /* trap and error numbers are mostly meaningless on ARM */
     275                 :          0 :         ret = notify_die(DIE_OOPS, str, regs, err, tsk->thread.trap_no, SIGSEGV);
     276                 :          0 :         if (ret == NOTIFY_STOP)
     277                 :            :                 return 1;
     278                 :            : 
     279                 :          0 :         print_modules();
     280                 :          0 :         __show_regs(regs);
     281                 :          0 :         pr_emerg("Process %.*s (pid: %d, stack limit = 0x%p)\n",
     282                 :            :                  TASK_COMM_LEN, tsk->comm, task_pid_nr(tsk), end_of_stack(tsk));
     283                 :            : 
     284                 :          0 :         if (!user_mode(regs) || in_interrupt()) {
     285                 :          0 :                 dump_mem(KERN_EMERG, "Stack: ", regs->ARM_sp,
     286                 :          0 :                          THREAD_SIZE + (unsigned long)task_stack_page(tsk));
     287                 :          0 :                 dump_backtrace(regs, tsk);
     288                 :          0 :                 dump_instr(KERN_EMERG, regs);
     289                 :            :         }
     290                 :            : 
     291                 :            :         return 0;
     292                 :            : }
     293                 :            : 
     294                 :            : static arch_spinlock_t die_lock = __ARCH_SPIN_LOCK_UNLOCKED;
     295                 :            : static int die_owner = -1;
     296                 :            : static unsigned int die_nest_count;
     297                 :            : 
     298                 :          0 : static unsigned long oops_begin(void)
     299                 :            : {
     300                 :            :         int cpu;
     301                 :            :         unsigned long flags;
     302                 :            : 
     303                 :          0 :         oops_enter();
     304                 :            : 
     305                 :            :         /* racy, but better than risking deadlock. */
     306                 :            :         raw_local_irq_save(flags);
     307                 :          0 :         cpu = smp_processor_id();
     308                 :          0 :         if (!arch_spin_trylock(&die_lock)) {
     309                 :          0 :                 if (cpu == die_owner)
     310                 :            :                         /* nested oops. should stop eventually */;
     311                 :            :                 else
     312                 :          0 :                         arch_spin_lock(&die_lock);
     313                 :            :         }
     314                 :          0 :         die_nest_count++;
     315                 :          0 :         die_owner = cpu;
     316                 :            :         console_verbose();
     317                 :          0 :         bust_spinlocks(1);
     318                 :          0 :         return flags;
     319                 :            : }
     320                 :            : 
     321                 :          0 : static void oops_end(unsigned long flags, struct pt_regs *regs, int signr)
     322                 :            : {
     323                 :            :         if (regs && kexec_should_crash(current))
     324                 :            :                 crash_kexec(regs);
     325                 :            : 
     326                 :          0 :         bust_spinlocks(0);
     327                 :          0 :         die_owner = -1;
     328                 :          0 :         add_taint(TAINT_DIE, LOCKDEP_NOW_UNRELIABLE);
     329                 :          0 :         die_nest_count--;
     330                 :          0 :         if (!die_nest_count)
     331                 :            :                 /* Nest count reaches zero, release the lock. */
     332                 :            :                 arch_spin_unlock(&die_lock);
     333                 :            :         raw_local_irq_restore(flags);
     334                 :          0 :         oops_exit();
     335                 :            : 
     336                 :          0 :         if (in_interrupt())
     337                 :          0 :                 panic("Fatal exception in interrupt");
     338                 :          0 :         if (panic_on_oops)
     339                 :          0 :                 panic("Fatal exception");
     340                 :          0 :         if (signr)
     341                 :          0 :                 do_exit(signr);
     342                 :          0 : }
     343                 :            : 
     344                 :            : /*
     345                 :            :  * This function is protected against re-entrancy.
     346                 :            :  */
     347                 :          0 : void die(const char *str, struct pt_regs *regs, int err)
     348                 :            : {
     349                 :            :         enum bug_trap_type bug_type = BUG_TRAP_TYPE_NONE;
     350                 :          0 :         unsigned long flags = oops_begin();
     351                 :            :         int sig = SIGSEGV;
     352                 :            : 
     353                 :          0 :         if (!user_mode(regs))
     354                 :          0 :                 bug_type = report_bug(regs->ARM_pc, regs);
     355                 :          0 :         if (bug_type != BUG_TRAP_TYPE_NONE)
     356                 :            :                 str = "Oops - BUG";
     357                 :            : 
     358                 :          0 :         if (__die(str, err, regs))
     359                 :            :                 sig = 0;
     360                 :            : 
     361                 :          0 :         oops_end(flags, regs, sig);
     362                 :          0 : }
     363                 :            : 
     364                 :          0 : void arm_notify_die(const char *str, struct pt_regs *regs,
     365                 :            :                 int signo, int si_code, void __user *addr,
     366                 :            :                 unsigned long err, unsigned long trap)
     367                 :            : {
     368                 :          0 :         if (user_mode(regs)) {
     369                 :          0 :                 current->thread.error_code = err;
     370                 :          0 :                 current->thread.trap_no = trap;
     371                 :            : 
     372                 :          0 :                 force_sig_fault(signo, si_code, addr);
     373                 :            :         } else {
     374                 :          0 :                 die(str, regs, err);
     375                 :            :         }
     376                 :          0 : }
     377                 :            : 
     378                 :            : #ifdef CONFIG_GENERIC_BUG
     379                 :            : 
     380                 :          0 : int is_valid_bugaddr(unsigned long pc)
     381                 :            : {
     382                 :            : #ifdef CONFIG_THUMB2_KERNEL
     383                 :            :         u16 bkpt;
     384                 :            :         u16 insn = __opcode_to_mem_thumb16(BUG_INSTR_VALUE);
     385                 :            : #else
     386                 :            :         u32 bkpt;
     387                 :            :         u32 insn = __opcode_to_mem_arm(BUG_INSTR_VALUE);
     388                 :            : #endif
     389                 :            : 
     390                 :          0 :         if (probe_kernel_address((unsigned *)pc, bkpt))
     391                 :            :                 return 0;
     392                 :            : 
     393                 :          0 :         return bkpt == insn;
     394                 :            : }
     395                 :            : 
     396                 :            : #endif
     397                 :            : 
     398                 :            : static LIST_HEAD(undef_hook);
     399                 :            : static DEFINE_RAW_SPINLOCK(undef_lock);
     400                 :            : 
     401                 :          3 : void register_undef_hook(struct undef_hook *hook)
     402                 :            : {
     403                 :            :         unsigned long flags;
     404                 :            : 
     405                 :          3 :         raw_spin_lock_irqsave(&undef_lock, flags);
     406                 :          3 :         list_add(&hook->node, &undef_hook);
     407                 :          3 :         raw_spin_unlock_irqrestore(&undef_lock, flags);
     408                 :          3 : }
     409                 :            : 
     410                 :          3 : void unregister_undef_hook(struct undef_hook *hook)
     411                 :            : {
     412                 :            :         unsigned long flags;
     413                 :            : 
     414                 :          3 :         raw_spin_lock_irqsave(&undef_lock, flags);
     415                 :            :         list_del(&hook->node);
     416                 :          3 :         raw_spin_unlock_irqrestore(&undef_lock, flags);
     417                 :          3 : }
     418                 :            : 
     419                 :            : static nokprobe_inline
     420                 :            : int call_undef_hook(struct pt_regs *regs, unsigned int instr)
     421                 :            : {
     422                 :            :         struct undef_hook *hook;
     423                 :            :         unsigned long flags;
     424                 :            :         int (*fn)(struct pt_regs *regs, unsigned int instr) = NULL;
     425                 :            : 
     426                 :          0 :         raw_spin_lock_irqsave(&undef_lock, flags);
     427                 :          0 :         list_for_each_entry(hook, &undef_hook, node)
     428                 :          0 :                 if ((instr & hook->instr_mask) == hook->instr_val &&
     429                 :          0 :                     (regs->ARM_cpsr & hook->cpsr_mask) == hook->cpsr_val)
     430                 :          0 :                         fn = hook->fn;
     431                 :          0 :         raw_spin_unlock_irqrestore(&undef_lock, flags);
     432                 :            : 
     433                 :          0 :         return fn ? fn(regs, instr) : 1;
     434                 :            : }
     435                 :            : 
     436                 :          0 : asmlinkage void do_undefinstr(struct pt_regs *regs)
     437                 :            : {
     438                 :            :         unsigned int instr;
     439                 :            :         void __user *pc;
     440                 :            : 
     441                 :          0 :         pc = (void __user *)instruction_pointer(regs);
     442                 :            : 
     443                 :          0 :         if (processor_mode(regs) == SVC_MODE) {
     444                 :            : #ifdef CONFIG_THUMB2_KERNEL
     445                 :            :                 if (thumb_mode(regs)) {
     446                 :            :                         instr = __mem_to_opcode_thumb16(((u16 *)pc)[0]);
     447                 :            :                         if (is_wide_instruction(instr)) {
     448                 :            :                                 u16 inst2;
     449                 :            :                                 inst2 = __mem_to_opcode_thumb16(((u16 *)pc)[1]);
     450                 :            :                                 instr = __opcode_thumb32_compose(instr, inst2);
     451                 :            :                         }
     452                 :            :                 } else
     453                 :            : #endif
     454                 :          0 :                         instr = __mem_to_opcode_arm(*(u32 *) pc);
     455                 :          0 :         } else if (thumb_mode(regs)) {
     456                 :          0 :                 if (get_user(instr, (u16 __user *)pc))
     457                 :            :                         goto die_sig;
     458                 :          0 :                 instr = __mem_to_opcode_thumb16(instr);
     459                 :          0 :                 if (is_wide_instruction(instr)) {
     460                 :            :                         unsigned int instr2;
     461                 :          0 :                         if (get_user(instr2, (u16 __user *)pc+1))
     462                 :            :                                 goto die_sig;
     463                 :            :                         instr2 = __mem_to_opcode_thumb16(instr2);
     464                 :          0 :                         instr = __opcode_thumb32_compose(instr, instr2);
     465                 :            :                 }
     466                 :            :         } else {
     467                 :          0 :                 if (get_user(instr, (u32 __user *)pc))
     468                 :            :                         goto die_sig;
     469                 :            :                 instr = __mem_to_opcode_arm(instr);
     470                 :            :         }
     471                 :            : 
     472                 :          0 :         if (call_undef_hook(regs, instr) == 0)
     473                 :          0 :                 return;
     474                 :            : 
     475                 :            : die_sig:
     476                 :            : #ifdef CONFIG_DEBUG_USER
     477                 :            :         if (user_debug & UDBG_UNDEFINED) {
     478                 :            :                 pr_info("%s (%d): undefined instruction: pc=%p\n",
     479                 :            :                         current->comm, task_pid_nr(current), pc);
     480                 :            :                 __show_regs(regs);
     481                 :            :                 dump_instr(KERN_INFO, regs);
     482                 :            :         }
     483                 :            : #endif
     484                 :          0 :         arm_notify_die("Oops - undefined instruction", regs,
     485                 :            :                        SIGILL, ILL_ILLOPC, pc, 0, 6);
     486                 :            : }
     487                 :            : NOKPROBE_SYMBOL(do_undefinstr)
     488                 :            : 
     489                 :            : /*
     490                 :            :  * Handle FIQ similarly to NMI on x86 systems.
     491                 :            :  *
     492                 :            :  * The runtime environment for NMIs is extremely restrictive
     493                 :            :  * (NMIs can pre-empt critical sections meaning almost all locking is
     494                 :            :  * forbidden) meaning this default FIQ handling must only be used in
     495                 :            :  * circumstances where non-maskability improves robustness, such as
     496                 :            :  * watchdog or debug logic.
     497                 :            :  *
     498                 :            :  * This handler is not appropriate for general purpose use in drivers
     499                 :            :  * platform code and can be overrideen using set_fiq_handler.
     500                 :            :  */
     501                 :          0 : asmlinkage void __exception_irq_entry handle_fiq_as_nmi(struct pt_regs *regs)
     502                 :            : {
     503                 :            :         struct pt_regs *old_regs = set_irq_regs(regs);
     504                 :            : 
     505                 :          0 :         nmi_enter();
     506                 :            : 
     507                 :            :         /* nop. FIQ handlers for special arch/arm features can be added here. */
     508                 :            : 
     509                 :          0 :         nmi_exit();
     510                 :            : 
     511                 :            :         set_irq_regs(old_regs);
     512                 :          0 : }
     513                 :            : 
     514                 :            : /*
     515                 :            :  * bad_mode handles the impossible case in the vectors.  If you see one of
     516                 :            :  * these, then it's extremely serious, and could mean you have buggy hardware.
     517                 :            :  * It never returns, and never tries to sync.  We hope that we can at least
     518                 :            :  * dump out some state information...
     519                 :            :  */
     520                 :          0 : asmlinkage void bad_mode(struct pt_regs *regs, int reason)
     521                 :            : {
     522                 :            :         console_verbose();
     523                 :            : 
     524                 :          0 :         pr_crit("Bad mode in %s handler detected\n", handler[reason]);
     525                 :            : 
     526                 :          0 :         die("Oops - bad mode", regs, 0);
     527                 :          0 :         local_irq_disable();
     528                 :          0 :         panic("bad mode");
     529                 :            : }
     530                 :            : 
     531                 :          0 : static int bad_syscall(int n, struct pt_regs *regs)
     532                 :            : {
     533                 :          0 :         if ((current->personality & PER_MASK) != PER_LINUX) {
     534                 :          0 :                 send_sig(SIGSEGV, current, 1);
     535                 :          0 :                 return regs->ARM_r0;
     536                 :            :         }
     537                 :            : 
     538                 :            : #ifdef CONFIG_DEBUG_USER
     539                 :            :         if (user_debug & UDBG_SYSCALL) {
     540                 :            :                 pr_err("[%d] %s: obsolete system call %08x.\n",
     541                 :            :                         task_pid_nr(current), current->comm, n);
     542                 :            :                 dump_instr(KERN_ERR, regs);
     543                 :            :         }
     544                 :            : #endif
     545                 :            : 
     546                 :          0 :         arm_notify_die("Oops - bad syscall", regs, SIGILL, ILL_ILLTRP,
     547                 :          0 :                        (void __user *)instruction_pointer(regs) -
     548                 :          0 :                          (thumb_mode(regs) ? 2 : 4),
     549                 :            :                        n, 0);
     550                 :            : 
     551                 :          0 :         return regs->ARM_r0;
     552                 :            : }
     553                 :            : 
     554                 :            : static inline int
     555                 :          1 : __do_cache_op(unsigned long start, unsigned long end)
     556                 :            : {
     557                 :            :         int ret;
     558                 :            : 
     559                 :            :         do {
     560                 :          1 :                 unsigned long chunk = min(PAGE_SIZE, end - start);
     561                 :            : 
     562                 :          1 :                 if (fatal_signal_pending(current))
     563                 :            :                         return 0;
     564                 :            : 
     565                 :          1 :                 ret = flush_cache_user_range(start, start + chunk);
     566                 :          1 :                 if (ret)
     567                 :          0 :                         return ret;
     568                 :            : 
     569                 :          1 :                 cond_resched();
     570                 :            :                 start += chunk;
     571                 :          1 :         } while (start < end);
     572                 :            : 
     573                 :            :         return 0;
     574                 :            : }
     575                 :            : 
     576                 :            : static inline int
     577                 :          1 : do_cache_op(unsigned long start, unsigned long end, int flags)
     578                 :            : {
     579                 :          1 :         if (end < start || flags)
     580                 :            :                 return -EINVAL;
     581                 :            : 
     582                 :          1 :         if (!access_ok(start, end - start))
     583                 :            :                 return -EFAULT;
     584                 :            : 
     585                 :          1 :         return __do_cache_op(start, end);
     586                 :            : }
     587                 :            : 
     588                 :            : /*
     589                 :            :  * Handle all unrecognised system calls.
     590                 :            :  *  0x9f0000 - 0x9fffff are some more esoteric system calls
     591                 :            :  */
     592                 :            : #define NR(x) ((__ARM_NR_##x) - __ARM_NR_BASE)
     593                 :          3 : asmlinkage int arm_syscall(int no, struct pt_regs *regs)
     594                 :            : {
     595                 :          3 :         if ((no >> 16) != (__ARM_NR_BASE>> 16))
     596                 :          0 :                 return bad_syscall(no, regs);
     597                 :            : 
     598                 :          3 :         switch (no & 0xffff) {
     599                 :            :         case 0: /* branch through 0 */
     600                 :          0 :                 arm_notify_die("branch through zero", regs,
     601                 :            :                                SIGSEGV, SEGV_MAPERR, NULL, 0, 0);
     602                 :          0 :                 return 0;
     603                 :            : 
     604                 :            :         case NR(breakpoint): /* SWI BREAK_POINT */
     605                 :          0 :                 regs->ARM_pc -= thumb_mode(regs) ? 2 : 4;
     606                 :          0 :                 ptrace_break(regs);
     607                 :          0 :                 return regs->ARM_r0;
     608                 :            : 
     609                 :            :         /*
     610                 :            :          * Flush a region from virtual address 'r0' to virtual address 'r1'
     611                 :            :          * _exclusive_.  There is no alignment requirement on either address;
     612                 :            :          * user space does not need to know the hardware cache layout.
     613                 :            :          *
     614                 :            :          * r2 contains flags.  It should ALWAYS be passed as ZERO until it
     615                 :            :          * is defined to be something else.  For now we ignore it, but may
     616                 :            :          * the fires of hell burn in your belly if you break this rule. ;)
     617                 :            :          *
     618                 :            :          * (at a later date, we may want to allow this call to not flush
     619                 :            :          * various aspects of the cache.  Passing '0' will guarantee that
     620                 :            :          * everything necessary gets flushed to maintain consistency in
     621                 :            :          * the specified region).
     622                 :            :          */
     623                 :            :         case NR(cacheflush):
     624                 :          1 :                 return do_cache_op(regs->ARM_r0, regs->ARM_r1, regs->ARM_r2);
     625                 :            : 
     626                 :            :         case NR(usr26):
     627                 :          0 :                 if (!(elf_hwcap & HWCAP_26BIT))
     628                 :            :                         break;
     629                 :          0 :                 regs->ARM_cpsr &= ~MODE32_BIT;
     630                 :          0 :                 return regs->ARM_r0;
     631                 :            : 
     632                 :            :         case NR(usr32):
     633                 :          0 :                 if (!(elf_hwcap & HWCAP_26BIT))
     634                 :            :                         break;
     635                 :          0 :                 regs->ARM_cpsr |= MODE32_BIT;
     636                 :          0 :                 return regs->ARM_r0;
     637                 :            : 
     638                 :            :         case NR(set_tls):
     639                 :          3 :                 set_tls(regs->ARM_r0);
     640                 :          3 :                 return 0;
     641                 :            : 
     642                 :            :         case NR(get_tls):
     643                 :          0 :                 return current_thread_info()->tp_value[0];
     644                 :            : 
     645                 :            :         default:
     646                 :            :                 /* Calls 9f00xx..9f07ff are defined to return -ENOSYS
     647                 :            :                    if not implemented, rather than raising SIGILL.  This
     648                 :            :                    way the calling program can gracefully determine whether
     649                 :            :                    a feature is supported.  */
     650                 :          0 :                 if ((no & 0xffff) <= 0x7ff)
     651                 :            :                         return -ENOSYS;
     652                 :            :                 break;
     653                 :            :         }
     654                 :            : #ifdef CONFIG_DEBUG_USER
     655                 :            :         /*
     656                 :            :          * experience shows that these seem to indicate that
     657                 :            :          * something catastrophic has happened
     658                 :            :          */
     659                 :            :         if (user_debug & UDBG_SYSCALL) {
     660                 :            :                 pr_err("[%d] %s: arm syscall %d\n",
     661                 :            :                        task_pid_nr(current), current->comm, no);
     662                 :            :                 dump_instr("", regs);
     663                 :            :                 if (user_mode(regs)) {
     664                 :            :                         __show_regs(regs);
     665                 :            :                         c_backtrace(frame_pointer(regs), processor_mode(regs));
     666                 :            :                 }
     667                 :            :         }
     668                 :            : #endif
     669                 :          0 :         arm_notify_die("Oops - bad syscall(2)", regs, SIGILL, ILL_ILLTRP,
     670                 :          0 :                        (void __user *)instruction_pointer(regs) -
     671                 :          0 :                          (thumb_mode(regs) ? 2 : 4),
     672                 :            :                        no, 0);
     673                 :          0 :         return 0;
     674                 :            : }
     675                 :            : 
     676                 :            : #ifdef CONFIG_TLS_REG_EMUL
     677                 :            : 
     678                 :            : /*
     679                 :            :  * We might be running on an ARMv6+ processor which should have the TLS
     680                 :            :  * register but for some reason we can't use it, or maybe an SMP system
     681                 :            :  * using a pre-ARMv6 processor (there are apparently a few prototypes like
     682                 :            :  * that in existence) and therefore access to that register must be
     683                 :            :  * emulated.
     684                 :            :  */
     685                 :            : 
     686                 :            : static int get_tp_trap(struct pt_regs *regs, unsigned int instr)
     687                 :            : {
     688                 :            :         int reg = (instr >> 12) & 15;
     689                 :            :         if (reg == 15)
     690                 :            :                 return 1;
     691                 :            :         regs->uregs[reg] = current_thread_info()->tp_value[0];
     692                 :            :         regs->ARM_pc += 4;
     693                 :            :         return 0;
     694                 :            : }
     695                 :            : 
     696                 :            : static struct undef_hook arm_mrc_hook = {
     697                 :            :         .instr_mask     = 0x0fff0fff,
     698                 :            :         .instr_val      = 0x0e1d0f70,
     699                 :            :         .cpsr_mask      = PSR_T_BIT,
     700                 :            :         .cpsr_val       = 0,
     701                 :            :         .fn             = get_tp_trap,
     702                 :            : };
     703                 :            : 
     704                 :            : static int __init arm_mrc_hook_init(void)
     705                 :            : {
     706                 :            :         register_undef_hook(&arm_mrc_hook);
     707                 :            :         return 0;
     708                 :            : }
     709                 :            : 
     710                 :            : late_initcall(arm_mrc_hook_init);
     711                 :            : 
     712                 :            : #endif
     713                 :            : 
     714                 :            : /*
     715                 :            :  * A data abort trap was taken, but we did not handle the instruction.
     716                 :            :  * Try to abort the user program, or panic if it was the kernel.
     717                 :            :  */
     718                 :            : asmlinkage void
     719                 :          0 : baddataabort(int code, unsigned long instr, struct pt_regs *regs)
     720                 :            : {
     721                 :          0 :         unsigned long addr = instruction_pointer(regs);
     722                 :            : 
     723                 :            : #ifdef CONFIG_DEBUG_USER
     724                 :            :         if (user_debug & UDBG_BADABORT) {
     725                 :            :                 pr_err("8<--- cut here ---\n");
     726                 :            :                 pr_err("[%d] %s: bad data abort: code %d instr 0x%08lx\n",
     727                 :            :                        task_pid_nr(current), current->comm, code, instr);
     728                 :            :                 dump_instr(KERN_ERR, regs);
     729                 :            :                 show_pte(KERN_ERR, current->mm, addr);
     730                 :            :         }
     731                 :            : #endif
     732                 :            : 
     733                 :          0 :         arm_notify_die("unknown data abort code", regs,
     734                 :            :                        SIGILL, ILL_ILLOPC, (void __user *)addr, instr, 0);
     735                 :          0 : }
     736                 :            : 
     737                 :          0 : void __readwrite_bug(const char *fn)
     738                 :            : {
     739                 :          0 :         pr_err("%s called, but not implemented\n", fn);
     740                 :          0 :         BUG();
     741                 :            : }
     742                 :            : EXPORT_SYMBOL(__readwrite_bug);
     743                 :            : 
     744                 :          0 : void __pte_error(const char *file, int line, pte_t pte)
     745                 :            : {
     746                 :          0 :         pr_err("%s:%d: bad pte %08llx.\n", file, line, (long long)pte_val(pte));
     747                 :          0 : }
     748                 :            : 
     749                 :          0 : void __pmd_error(const char *file, int line, pmd_t pmd)
     750                 :            : {
     751                 :          0 :         pr_err("%s:%d: bad pmd %08llx.\n", file, line, (long long)pmd_val(pmd));
     752                 :          0 : }
     753                 :            : 
     754                 :          0 : void __pgd_error(const char *file, int line, pgd_t pgd)
     755                 :            : {
     756                 :          0 :         pr_err("%s:%d: bad pgd %08llx.\n", file, line, (long long)pgd_val(pgd));
     757                 :          0 : }
     758                 :            : 
     759                 :          0 : asmlinkage void __div0(void)
     760                 :            : {
     761                 :          0 :         pr_err("Division by zero in kernel.\n");
     762                 :          0 :         dump_stack();
     763                 :          0 : }
     764                 :            : EXPORT_SYMBOL(__div0);
     765                 :            : 
     766                 :          0 : void abort(void)
     767                 :            : {
     768                 :          0 :         BUG();
     769                 :            : 
     770                 :            :         /* if that doesn't kill us, halt */
     771                 :            :         panic("Oops failed to kill thread");
     772                 :            : }
     773                 :            : 
     774                 :          3 : void __init trap_init(void)
     775                 :            : {
     776                 :          3 :         return;
     777                 :            : }
     778                 :            : 
     779                 :            : #ifdef CONFIG_KUSER_HELPERS
     780                 :          3 : static void __init kuser_init(void *vectors)
     781                 :            : {
     782                 :            :         extern char __kuser_helper_start[], __kuser_helper_end[];
     783                 :          3 :         int kuser_sz = __kuser_helper_end - __kuser_helper_start;
     784                 :            : 
     785                 :          3 :         memcpy(vectors + 0x1000 - kuser_sz, __kuser_helper_start, kuser_sz);
     786                 :            : 
     787                 :            :         /*
     788                 :            :          * vectors + 0xfe0 = __kuser_get_tls
     789                 :            :          * vectors + 0xfe8 = hardware TLS instruction at 0xffff0fe8
     790                 :            :          */
     791                 :            :         if (tls_emu || has_tls_reg)
     792                 :          3 :                 memcpy(vectors + 0xfe0, vectors + 0xfe8, 4);
     793                 :          3 : }
     794                 :            : #else
     795                 :            : static inline void __init kuser_init(void *vectors)
     796                 :            : {
     797                 :            : }
     798                 :            : #endif
     799                 :            : 
     800                 :          3 : void __init early_trap_init(void *vectors_base)
     801                 :            : {
     802                 :            : #ifndef CONFIG_CPU_V7M
     803                 :          3 :         unsigned long vectors = (unsigned long)vectors_base;
     804                 :            :         extern char __stubs_start[], __stubs_end[];
     805                 :            :         extern char __vectors_start[], __vectors_end[];
     806                 :            :         unsigned i;
     807                 :            : 
     808                 :          3 :         vectors_page = vectors_base;
     809                 :            : 
     810                 :            :         /*
     811                 :            :          * Poison the vectors page with an undefined instruction.  This
     812                 :            :          * instruction is chosen to be undefined for both ARM and Thumb
     813                 :            :          * ISAs.  The Thumb version is an undefined instruction with a
     814                 :            :          * branch back to the undefined instruction.
     815                 :            :          */
     816                 :          3 :         for (i = 0; i < PAGE_SIZE / sizeof(u32); i++)
     817                 :          3 :                 ((u32 *)vectors_base)[i] = 0xe7fddef1;
     818                 :            : 
     819                 :            :         /*
     820                 :            :          * Copy the vectors, stubs and kuser helpers (in entry-armv.S)
     821                 :            :          * into the vector page, mapped at 0xffff0000, and ensure these
     822                 :            :          * are visible to the instruction stream.
     823                 :            :          */
     824                 :          3 :         memcpy((void *)vectors, __vectors_start, __vectors_end - __vectors_start);
     825                 :          3 :         memcpy((void *)vectors + 0x1000, __stubs_start, __stubs_end - __stubs_start);
     826                 :            : 
     827                 :          3 :         kuser_init(vectors_base);
     828                 :            : 
     829                 :          3 :         flush_icache_range(vectors, vectors + PAGE_SIZE * 2);
     830                 :            : #else /* ifndef CONFIG_CPU_V7M */
     831                 :            :         /*
     832                 :            :          * on V7-M there is no need to copy the vector table to a dedicated
     833                 :            :          * memory area. The address is configurable and so a table in the kernel
     834                 :            :          * image can be used.
     835                 :            :          */
     836                 :            : #endif
     837                 :          3 : }
    

Generated by: LCOV version 1.14