traps.c 9.1 KB

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