traps.c 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431
  1. /*
  2. * Copyright (C) 2004-2006 Atmel Corporation
  3. *
  4. * This program is free software; you can redistribute it and/or modify
  5. * it under the terms of the GNU General Public License version 2 as
  6. * published by the Free Software Foundation.
  7. */
  8. #undef DEBUG
  9. #include <linux/sched.h>
  10. #include <linux/init.h>
  11. #include <linux/module.h>
  12. #include <linux/kallsyms.h>
  13. #include <linux/notifier.h>
  14. #include <asm/traps.h>
  15. #include <asm/sysreg.h>
  16. #include <asm/addrspace.h>
  17. #include <asm/ocd.h>
  18. #include <asm/mmu_context.h>
  19. #include <asm/uaccess.h>
  20. static void dump_mem(const char *str, unsigned long bottom, unsigned long top)
  21. {
  22. unsigned long p;
  23. int i;
  24. printk("%s(0x%08lx to 0x%08lx)\n", str, bottom, top);
  25. for (p = bottom & ~31; p < top; ) {
  26. printk("%04lx: ", p & 0xffff);
  27. for (i = 0; i < 8; i++, p += 4) {
  28. unsigned int val;
  29. if (p < bottom || p >= top)
  30. printk(" ");
  31. else {
  32. if (__get_user(val, (unsigned int __user *)p)) {
  33. printk("\n");
  34. goto out;
  35. }
  36. printk("%08x ", val);
  37. }
  38. }
  39. printk("\n");
  40. }
  41. out:
  42. return;
  43. }
  44. static inline int valid_stack_ptr(struct thread_info *tinfo, unsigned long p)
  45. {
  46. return (p > (unsigned long)tinfo)
  47. && (p < (unsigned long)tinfo + THREAD_SIZE - 3);
  48. }
  49. #ifdef CONFIG_FRAME_POINTER
  50. static inline void __show_trace(struct task_struct *tsk, unsigned long *sp,
  51. struct pt_regs *regs)
  52. {
  53. unsigned long lr, fp;
  54. struct thread_info *tinfo;
  55. tinfo = (struct thread_info *)
  56. ((unsigned long)sp & ~(THREAD_SIZE - 1));
  57. if (regs)
  58. fp = regs->r7;
  59. else if (tsk == current)
  60. asm("mov %0, r7" : "=r"(fp));
  61. else
  62. fp = tsk->thread.cpu_context.r7;
  63. /*
  64. * Walk the stack as long as the frame pointer (a) is within
  65. * the kernel stack of the task, and (b) it doesn't move
  66. * downwards.
  67. */
  68. while (valid_stack_ptr(tinfo, fp)) {
  69. unsigned long new_fp;
  70. lr = *(unsigned long *)fp;
  71. printk(" [<%08lx>] ", lr);
  72. print_symbol("%s\n", lr);
  73. new_fp = *(unsigned long *)(fp + 4);
  74. if (new_fp <= fp)
  75. break;
  76. fp = new_fp;
  77. }
  78. printk("\n");
  79. }
  80. #else
  81. static inline void __show_trace(struct task_struct *tsk, unsigned long *sp,
  82. struct pt_regs *regs)
  83. {
  84. unsigned long addr;
  85. while (!kstack_end(sp)) {
  86. addr = *sp++;
  87. if (kernel_text_address(addr)) {
  88. printk(" [<%08lx>] ", addr);
  89. print_symbol("%s\n", addr);
  90. }
  91. }
  92. }
  93. #endif
  94. void show_trace(struct task_struct *tsk, unsigned long *sp,
  95. struct pt_regs *regs)
  96. {
  97. if (regs &&
  98. (((regs->sr & MODE_MASK) == MODE_EXCEPTION) ||
  99. ((regs->sr & MODE_MASK) == MODE_USER)))
  100. return;
  101. printk ("Call trace:");
  102. #ifdef CONFIG_KALLSYMS
  103. printk("\n");
  104. #endif
  105. __show_trace(tsk, sp, regs);
  106. printk("\n");
  107. }
  108. void show_stack(struct task_struct *tsk, unsigned long *sp)
  109. {
  110. unsigned long stack;
  111. if (!tsk)
  112. tsk = current;
  113. if (sp == 0) {
  114. if (tsk == current) {
  115. register unsigned long *real_sp __asm__("sp");
  116. sp = real_sp;
  117. } else {
  118. sp = (unsigned long *)tsk->thread.cpu_context.ksp;
  119. }
  120. }
  121. stack = (unsigned long)sp;
  122. dump_mem("Stack: ", stack,
  123. THREAD_SIZE + (unsigned long)tsk->thread_info);
  124. show_trace(tsk, sp, NULL);
  125. }
  126. void dump_stack(void)
  127. {
  128. show_stack(NULL, NULL);
  129. }
  130. EXPORT_SYMBOL(dump_stack);
  131. ATOMIC_NOTIFIER_HEAD(avr32_die_chain);
  132. int register_die_notifier(struct notifier_block *nb)
  133. {
  134. pr_debug("register_die_notifier: %p\n", nb);
  135. return atomic_notifier_chain_register(&avr32_die_chain, nb);
  136. }
  137. EXPORT_SYMBOL(register_die_notifier);
  138. int unregister_die_notifier(struct notifier_block *nb)
  139. {
  140. return atomic_notifier_chain_unregister(&avr32_die_chain, nb);
  141. }
  142. EXPORT_SYMBOL(unregister_die_notifier);
  143. static DEFINE_SPINLOCK(die_lock);
  144. void __die(const char *str, struct pt_regs *regs, unsigned long err,
  145. const char *file, const char *func, unsigned long line)
  146. {
  147. struct task_struct *tsk = current;
  148. static int die_counter;
  149. console_verbose();
  150. spin_lock_irq(&die_lock);
  151. bust_spinlocks(1);
  152. printk(KERN_ALERT "%s", str);
  153. if (file && func)
  154. printk(" in %s:%s, line %ld", file, func, line);
  155. printk("[#%d]:\n", ++die_counter);
  156. print_modules();
  157. show_regs(regs);
  158. printk("Process %s (pid: %d, stack limit = 0x%p)\n",
  159. tsk->comm, tsk->pid, tsk->thread_info + 1);
  160. if (!user_mode(regs) || in_interrupt()) {
  161. dump_mem("Stack: ", regs->sp,
  162. THREAD_SIZE + (unsigned long)tsk->thread_info);
  163. }
  164. bust_spinlocks(0);
  165. spin_unlock_irq(&die_lock);
  166. do_exit(SIGSEGV);
  167. }
  168. void __die_if_kernel(const char *str, struct pt_regs *regs, unsigned long err,
  169. const char *file, const char *func, unsigned long line)
  170. {
  171. if (!user_mode(regs))
  172. __die(str, regs, err, file, func, line);
  173. }
  174. asmlinkage void do_nmi(unsigned long ecr, struct pt_regs *regs)
  175. {
  176. #ifdef CONFIG_SUBARCH_AVR32B
  177. /*
  178. * The exception entry always saves RSR_EX. For NMI, this is
  179. * wrong; it should be RSR_NMI
  180. */
  181. regs->sr = sysreg_read(RSR_NMI);
  182. #endif
  183. printk("NMI taken!!!!\n");
  184. die("NMI", regs, ecr);
  185. BUG();
  186. }
  187. asmlinkage void do_critical_exception(unsigned long ecr, struct pt_regs *regs)
  188. {
  189. printk("Unable to handle critical exception %lu at pc = %08lx!\n",
  190. ecr, regs->pc);
  191. die("Oops", regs, ecr);
  192. BUG();
  193. }
  194. asmlinkage void do_address_exception(unsigned long ecr, struct pt_regs *regs)
  195. {
  196. siginfo_t info;
  197. die_if_kernel("Oops: Address exception in kernel mode", regs, ecr);
  198. #ifdef DEBUG
  199. if (ecr == ECR_ADDR_ALIGN_X)
  200. pr_debug("Instruction Address Exception at pc = %08lx\n",
  201. regs->pc);
  202. else if (ecr == ECR_ADDR_ALIGN_R)
  203. pr_debug("Data Address Exception (Read) at pc = %08lx\n",
  204. regs->pc);
  205. else if (ecr == ECR_ADDR_ALIGN_W)
  206. pr_debug("Data Address Exception (Write) at pc = %08lx\n",
  207. regs->pc);
  208. else
  209. BUG();
  210. show_regs(regs);
  211. #endif
  212. info.si_signo = SIGBUS;
  213. info.si_errno = 0;
  214. info.si_code = BUS_ADRALN;
  215. info.si_addr = (void __user *)regs->pc;
  216. force_sig_info(SIGBUS, &info, current);
  217. }
  218. /* This way of handling undefined instructions is stolen from ARM */
  219. static LIST_HEAD(undef_hook);
  220. static spinlock_t undef_lock = SPIN_LOCK_UNLOCKED;
  221. void register_undef_hook(struct undef_hook *hook)
  222. {
  223. spin_lock_irq(&undef_lock);
  224. list_add(&hook->node, &undef_hook);
  225. spin_unlock_irq(&undef_lock);
  226. }
  227. void unregister_undef_hook(struct undef_hook *hook)
  228. {
  229. spin_lock_irq(&undef_lock);
  230. list_del(&hook->node);
  231. spin_unlock_irq(&undef_lock);
  232. }
  233. static int do_cop_absent(u32 insn)
  234. {
  235. int cop_nr;
  236. u32 cpucr;
  237. if ( (insn & 0xfdf00000) == 0xf1900000 )
  238. /* LDC0 */
  239. cop_nr = 0;
  240. else
  241. cop_nr = (insn >> 13) & 0x7;
  242. /* Try enabling the coprocessor */
  243. cpucr = sysreg_read(CPUCR);
  244. cpucr |= (1 << (24 + cop_nr));
  245. sysreg_write(CPUCR, cpucr);
  246. cpucr = sysreg_read(CPUCR);
  247. if ( !(cpucr & (1 << (24 + cop_nr))) ){
  248. printk("Coprocessor #%i not found!\n", cop_nr);
  249. return -1;
  250. }
  251. return 0;
  252. }
  253. #ifdef CONFIG_BUG
  254. #ifdef CONFIG_DEBUG_BUGVERBOSE
  255. static inline void do_bug_verbose(struct pt_regs *regs, u32 insn)
  256. {
  257. char *file;
  258. u16 line;
  259. char c;
  260. if (__get_user(line, (u16 __user *)(regs->pc + 2)))
  261. return;
  262. if (__get_user(file, (char * __user *)(regs->pc + 4))
  263. || (unsigned long)file < PAGE_OFFSET
  264. || __get_user(c, file))
  265. file = "<bad filename>";
  266. printk(KERN_ALERT "kernel BUG at %s:%d!\n", file, line);
  267. }
  268. #else
  269. static inline void do_bug_verbose(struct pt_regs *regs, u32 insn)
  270. {
  271. }
  272. #endif
  273. #endif
  274. asmlinkage void do_illegal_opcode(unsigned long ecr, struct pt_regs *regs)
  275. {
  276. u32 insn;
  277. struct undef_hook *hook;
  278. siginfo_t info;
  279. void __user *pc;
  280. if (!user_mode(regs))
  281. goto kernel_trap;
  282. local_irq_enable();
  283. pc = (void __user *)instruction_pointer(regs);
  284. if (__get_user(insn, (u32 __user *)pc))
  285. goto invalid_area;
  286. if (ecr == ECR_COPROC_ABSENT) {
  287. if (do_cop_absent(insn) == 0)
  288. return;
  289. }
  290. spin_lock_irq(&undef_lock);
  291. list_for_each_entry(hook, &undef_hook, node) {
  292. if ((insn & hook->insn_mask) == hook->insn_val) {
  293. if (hook->fn(regs, insn) == 0) {
  294. spin_unlock_irq(&undef_lock);
  295. return;
  296. }
  297. }
  298. }
  299. spin_unlock_irq(&undef_lock);
  300. invalid_area:
  301. #ifdef DEBUG
  302. printk("Illegal instruction at pc = %08lx\n", regs->pc);
  303. if (regs->pc < TASK_SIZE) {
  304. unsigned long ptbr, pgd, pte, *p;
  305. ptbr = sysreg_read(PTBR);
  306. p = (unsigned long *)ptbr;
  307. pgd = p[regs->pc >> 22];
  308. p = (unsigned long *)((pgd & 0x1ffff000) | 0x80000000);
  309. pte = p[(regs->pc >> 12) & 0x3ff];
  310. printk("page table: 0x%08lx -> 0x%08lx -> 0x%08lx\n", ptbr, pgd, pte);
  311. }
  312. #endif
  313. info.si_signo = SIGILL;
  314. info.si_errno = 0;
  315. info.si_addr = (void __user *)regs->pc;
  316. switch (ecr) {
  317. case ECR_ILLEGAL_OPCODE:
  318. case ECR_UNIMPL_INSTRUCTION:
  319. info.si_code = ILL_ILLOPC;
  320. break;
  321. case ECR_PRIVILEGE_VIOLATION:
  322. info.si_code = ILL_PRVOPC;
  323. break;
  324. case ECR_COPROC_ABSENT:
  325. info.si_code = ILL_COPROC;
  326. break;
  327. default:
  328. BUG();
  329. }
  330. force_sig_info(SIGILL, &info, current);
  331. return;
  332. kernel_trap:
  333. #ifdef CONFIG_BUG
  334. if (__kernel_text_address(instruction_pointer(regs))) {
  335. insn = *(u16 *)instruction_pointer(regs);
  336. if (insn == AVR32_BUG_OPCODE) {
  337. do_bug_verbose(regs, insn);
  338. die("Kernel BUG", regs, 0);
  339. return;
  340. }
  341. }
  342. #endif
  343. die("Oops: Illegal instruction in kernel code", regs, ecr);
  344. }
  345. asmlinkage void do_fpe(unsigned long ecr, struct pt_regs *regs)
  346. {
  347. siginfo_t info;
  348. printk("Floating-point exception at pc = %08lx\n", regs->pc);
  349. /* We have no FPU... */
  350. info.si_signo = SIGILL;
  351. info.si_errno = 0;
  352. info.si_addr = (void __user *)regs->pc;
  353. info.si_code = ILL_COPROC;
  354. force_sig_info(SIGILL, &info, current);
  355. }
  356. void __init trap_init(void)
  357. {
  358. }