traps.c
上传用户:lgb322
上传日期:2013-02-24
资源大小:30529k
文件大小:13k
源码类别:

嵌入式Linux

开发平台:

Unix_Linux

  1. /* $Id: traps.c,v 1.14 2001/07/24 08:07:10 gniibe Exp $
  2.  *
  3.  *  linux/arch/sh/traps.c
  4.  *
  5.  *  SuperH version: Copyright (C) 1999 Niibe Yutaka
  6.  *                  Copyright (C) 2000 Philipp Rumpf
  7.  *                  Copyright (C) 2000 David Howells
  8.  */
  9. /*
  10.  * 'Traps.c' handles hardware traps and faults after we have saved some
  11.  * state in 'entry.S'.
  12.  */
  13. #include <linux/config.h>
  14. #include <linux/sched.h>
  15. #include <linux/kernel.h>
  16. #include <linux/string.h>
  17. #include <linux/errno.h>
  18. #include <linux/ptrace.h>
  19. #include <linux/timer.h>
  20. #include <linux/mm.h>
  21. #include <linux/smp.h>
  22. #include <linux/smp_lock.h>
  23. #include <linux/init.h>
  24. #include <linux/delay.h>
  25. #include <linux/spinlock.h>
  26. #include <asm/system.h>
  27. #include <asm/uaccess.h>
  28. #include <asm/io.h>
  29. #include <asm/atomic.h>
  30. #include <asm/processor.h>
  31. #define DO_ERROR(trapnr, signr, str, name, tsk) 
  32. asmlinkage void do_##name(unsigned long r4, unsigned long r5, 
  33.   unsigned long r6, unsigned long r7, 
  34.   struct pt_regs regs) 
  35. unsigned long error_code; 
  36.  
  37. asm volatile("stc r2_bank, %0": "=r" (error_code)); 
  38. sti(); 
  39. tsk->thread.error_code = error_code; 
  40. tsk->thread.trap_no = trapnr; 
  41. force_sig(signr, tsk); 
  42. die_if_no_fixup(str,&regs,error_code); 
  43. }
  44. /*
  45.  * These constants are for searching for possible module text
  46.  * segments.  VMALLOC_OFFSET comes from mm/vmalloc.c; MODULE_RANGE is
  47.  * a guess of how much space is likely to be vmalloced.
  48.  */
  49. #define VMALLOC_OFFSET (8*1024*1024)
  50. #define MODULE_RANGE (8*1024*1024)
  51. spinlock_t die_lock;
  52. void die(const char * str, struct pt_regs * regs, long err)
  53. {
  54. console_verbose();
  55. spin_lock_irq(&die_lock);
  56. printk("%s: %04lxn", str, err & 0xffff);
  57. show_regs(regs);
  58. spin_unlock_irq(&die_lock);
  59. do_exit(SIGSEGV);
  60. }
  61. static inline void die_if_kernel(const char * str, struct pt_regs * regs, long err)
  62. {
  63. if (!user_mode(regs))
  64. die(str, regs, err);
  65. }
  66. static int handle_unaligned_notify_count = 10;
  67. /*
  68.  * try and fix up kernelspace address errors
  69.  * - userspace errors just cause EFAULT to be returned, resulting in SEGV
  70.  * - kernel/userspace interfaces cause a jump to an appropriate handler
  71.  * - other kernel errors are bad
  72.  * - return 0 if fixed-up, -EFAULT if non-fatal (to the kernel) fault
  73.  */
  74. static int die_if_no_fixup(const char * str, struct pt_regs * regs, long err)
  75. {
  76. if (!user_mode(regs))
  77. {
  78. unsigned long fixup;
  79. fixup = search_exception_table(regs->pc);
  80. if (fixup) {
  81. regs->pc = fixup;
  82. return 0;
  83. }
  84. die(str, regs, err);
  85. }
  86. return -EFAULT;
  87. }
  88. /*
  89.  * handle an instruction that does an unaligned memory access by emulating the
  90.  * desired behaviour
  91.  * - note that PC _may not_ point to the faulting instruction
  92.  *   (if that instruction is in a branch delay slot)
  93.  * - return 0 if emulation okay, -EFAULT on existential error
  94.  */
  95. static int handle_unaligned_ins(u16 instruction, struct pt_regs *regs)
  96. {
  97. int ret, index, count;
  98. unsigned long *rm, *rn;
  99. unsigned char *src, *dst;
  100. index = (instruction>>8)&15; /* 0x0F00 */
  101. rn = &regs->regs[index];
  102. index = (instruction>>4)&15; /* 0x00F0 */
  103. rm = &regs->regs[index];
  104. count = 1<<(instruction&3);
  105. ret = -EFAULT;
  106. switch (instruction>>12) {
  107. case 0: /* mov.[bwl] to/from memory via r0+rn */
  108. if (instruction & 8) {
  109. /* from memory */
  110. src = (unsigned char*) *rm;
  111. src += regs->regs[0];
  112. dst = (unsigned char*) rn;
  113. *(unsigned long*)dst = 0;
  114. #ifdef __LITTLE_ENDIAN__
  115. if (copy_from_user(dst, src, count))
  116. goto fetch_fault;
  117. if ((count == 2) && dst[1] & 0x80) {
  118. dst[2] = 0xff;
  119. dst[3] = 0xff;
  120. }
  121. #else
  122. dst += 4-count;
  123. if (__copy_user(dst, src, count))
  124. goto fetch_fault;
  125. if ((count == 2) && dst[2] & 0x80) {
  126. dst[0] = 0xff;
  127. dst[1] = 0xff;
  128. }
  129. #endif
  130. } else {
  131. /* to memory */
  132. src = (unsigned char*) rm;
  133. #if !defined(__LITTLE_ENDIAN__)
  134. src += 4-count;
  135. #endif
  136. dst = (unsigned char*) *rn;
  137. dst += regs->regs[0];
  138. if (copy_to_user(dst, src, count))
  139. goto fetch_fault;
  140. }
  141. ret = 0;
  142. break;
  143. case 1: /* mov.l Rm,@(disp,Rn) */
  144. src = (unsigned char*) rm;
  145. dst = (unsigned char*) *rn;
  146. dst += (instruction&0x000F)<<2;
  147. if (copy_to_user(dst,src,4))
  148. goto fetch_fault;
  149. ret = 0;
  150.   break;
  151. case 2: /* mov.[bwl] to memory, possibly with pre-decrement */
  152. if (instruction & 4)
  153. *rn -= count;
  154. src = (unsigned char*) rm;
  155. dst = (unsigned char*) *rn;
  156. #if !defined(__LITTLE_ENDIAN__)
  157. src += 4-count;
  158. #endif
  159. if (copy_to_user(dst, src, count))
  160. goto fetch_fault;
  161. ret = 0;
  162. break;
  163. case 5: /* mov.l @(disp,Rm),Rn */
  164. src = (unsigned char*) *rm;
  165. src += (instruction&0x000F)<<2;
  166. dst = (unsigned char*) rn;
  167. *(unsigned long*)dst = 0;
  168. if (copy_from_user(dst,src,4))
  169. goto fetch_fault;
  170. ret = 0;
  171.   break;
  172. case 6: /* mov.[bwl] from memory, possibly with post-increment */
  173. src = (unsigned char*) *rm;
  174. if (instruction & 4)
  175. *rm += count;
  176. dst = (unsigned char*) rn;
  177. *(unsigned long*)dst = 0;
  178. #ifdef __LITTLE_ENDIAN__
  179. if (copy_from_user(dst, src, count))
  180. goto fetch_fault;
  181. if ((count == 2) && dst[1] & 0x80) {
  182. dst[2] = 0xff;
  183. dst[3] = 0xff;
  184. }
  185. #else
  186. dst += 4-count;
  187. if (copy_from_user(dst, src, count))
  188. goto fetch_fault;
  189. if ((count == 2) && dst[2] & 0x80) {
  190. dst[0] = 0xff;
  191. dst[1] = 0xff;
  192. }
  193. #endif
  194. ret = 0;
  195. break;
  196. case 8:
  197. switch ((instruction&0xFF00)>>8) {
  198. case 0x81: /* mov.w R0,@(disp,Rn) */
  199. src = (unsigned char*) &regs->regs[0];
  200. #if !defined(__LITTLE_ENDIAN__)
  201. src += 2;
  202. #endif
  203. dst = (unsigned char*) *rm; /* called Rn in the spec */
  204. dst += (instruction&0x000F)<<1;
  205. if (copy_to_user(dst, src, 2))
  206. goto fetch_fault;
  207. ret = 0;
  208. break;
  209. case 0x85: /* mov.w @(disp,Rm),R0 */
  210. src = (unsigned char*) *rm;
  211. src += (instruction&0x000F)<<1;
  212. dst = (unsigned char*) &regs->regs[0];
  213. *(unsigned long*)dst = 0;
  214. #if !defined(__LITTLE_ENDIAN__)
  215. dst += 2;
  216. #endif
  217. if (copy_from_user(dst, src, 2))
  218. goto fetch_fault;
  219. #ifdef __LITTLE_ENDIAN__
  220. if (dst[1] & 0x80) {
  221. dst[2] = 0xff;
  222. dst[3] = 0xff;
  223. }
  224. #else
  225. if (dst[2] & 0x80) {
  226. dst[0] = 0xff;
  227. dst[1] = 0xff;
  228. }
  229. #endif
  230. ret = 0;
  231. break;
  232. }
  233. break;
  234. }
  235. return ret;
  236.  fetch_fault:
  237. /* Argh. Address not only misaligned but also non-existent.
  238.  * Raise an EFAULT and see if it's trapped
  239.  */
  240. return die_if_no_fixup("Fault in unaligned fixup", regs, 0);
  241. }
  242. /*
  243.  * emulate the instruction in the delay slot
  244.  * - fetches the instruction from PC+2
  245.  */
  246. static inline int handle_unaligned_delayslot(struct pt_regs *regs)
  247. {
  248. u16 instruction;
  249. if (copy_from_user(&instruction, (u16 *)(regs->pc+2), 2)) {
  250. /* the instruction-fetch faulted */
  251. if (user_mode(regs))
  252. return -EFAULT;
  253. /* kernel */
  254. die("delay-slot-insn faulting in handle_unaligned_delayslot", regs, 0);
  255. }
  256. return handle_unaligned_ins(instruction,regs);
  257. }
  258. /*
  259.  * handle an instruction that does an unaligned memory access
  260.  * - have to be careful of branch delay-slot instructions that fault
  261.  *   - if the branch would be taken PC points to the branch
  262.  *   - if the branch would not be taken, PC points to delay-slot
  263.  * - return 0 if handled, -EFAULT if failed (may not return if in kernel)
  264.  */
  265. static int handle_unaligned_access(u16 instruction, struct pt_regs *regs)
  266. {
  267. u_int rm;
  268. int ret, index;
  269. index = (instruction>>8)&15; /* 0x0F00 */
  270. rm = regs->regs[index];
  271. /* shout about the first ten userspace fixups */
  272. if (user_mode(regs) && handle_unaligned_notify_count>0) {
  273. handle_unaligned_notify_count--;
  274. printk("Fixing up unaligned userspace access in "%s" pid=%d pc=0x%p ins=0x%04hxn",
  275.        current->comm,current->pid,(u16*)regs->pc,instruction);
  276. }
  277. ret = -EFAULT;
  278. switch (instruction&0xF000) {
  279. case 0x0000:
  280. if (instruction==0x000B) {
  281. /* rts */
  282. ret = handle_unaligned_delayslot(regs);
  283. if (ret==0)
  284. regs->pc = regs->pr;
  285. }
  286. else if ((instruction&0x00FF)==0x0023) {
  287. /* braf @Rm */
  288. ret = handle_unaligned_delayslot(regs);
  289. if (ret==0)
  290. regs->pc += rm + 4;
  291. }
  292. else if ((instruction&0x00FF)==0x0003) {
  293. /* bsrf @Rm */
  294. ret = handle_unaligned_delayslot(regs);
  295. if (ret==0) {
  296. regs->pr = regs->pc + 4;
  297. regs->pc += rm + 4;
  298. }
  299. }
  300. else {
  301. /* mov.[bwl] to/from memory via r0+rn */
  302. goto simple;
  303. }
  304. break;
  305. case 0x1000: /* mov.l Rm,@(disp,Rn) */
  306. goto simple;
  307. case 0x2000: /* mov.[bwl] to memory, possibly with pre-decrement */
  308. goto simple;
  309. case 0x4000:
  310. if ((instruction&0x00FF)==0x002B) {
  311. /* jmp @Rm */
  312. ret = handle_unaligned_delayslot(regs);
  313. if (ret==0)
  314. regs->pc = rm;
  315. }
  316. else if ((instruction&0x00FF)==0x000B) {
  317. /* jsr @Rm */
  318. ret = handle_unaligned_delayslot(regs);
  319. if (ret==0) {
  320. regs->pr = regs->pc + 4;
  321. regs->pc = rm;
  322. }
  323. }
  324. else {
  325. /* mov.[bwl] to/from memory via r0+rn */
  326. goto simple;
  327. }
  328. break;
  329. case 0x5000: /* mov.l @(disp,Rm),Rn */
  330. goto simple;
  331. case 0x6000: /* mov.[bwl] from memory, possibly with post-increment */
  332. goto simple;
  333. case 0x8000: /* bf lab, bf/s lab, bt lab, bt/s lab */
  334. switch (instruction&0x0F00) {
  335. case 0x0100: /* mov.w R0,@(disp,Rm) */
  336. goto simple;
  337. case 0x0500: /* mov.w @(disp,Rm),R0 */
  338. goto simple;
  339. case 0x0B00: /* bf   lab - no delayslot*/
  340. break;
  341. case 0x0F00: /* bf/s lab */
  342. ret = handle_unaligned_delayslot(regs);
  343. if (ret==0)
  344. regs->pc += (instruction&0x00FF)*2 + 4;
  345. break;
  346. case 0x0900: /* bt   lab - no delayslot */
  347. break;
  348. case 0x0D00: /* bt/s lab */
  349. ret = handle_unaligned_delayslot(regs);
  350. if (ret==0)
  351. regs->pc += (instruction&0x00FF)*2 + 4;
  352. break;
  353. }
  354. break;
  355. case 0xA000: /* bra label */
  356. ret = handle_unaligned_delayslot(regs);
  357. if (ret==0)
  358. regs->pc += (instruction&0x0FFF)*2 + 4;
  359. break;
  360. case 0xB000: /* bsr label */
  361. ret = handle_unaligned_delayslot(regs);
  362. if (ret==0) {
  363. regs->pr = regs->pc + 4;
  364. regs->pc += (instruction&0x0FFF)*2 + 4;
  365. }
  366. break;
  367. }
  368. return ret;
  369. /* handle non-delay-slot instruction */
  370.  simple:
  371. ret = handle_unaligned_ins(instruction,regs);
  372. if (ret==0)
  373. regs->pc += 2;
  374. return ret;
  375. }
  376. /*
  377.  * Handle various address error exceptions
  378.  */
  379. asmlinkage void do_address_error(struct pt_regs *regs, 
  380.  unsigned long writeaccess,
  381.  unsigned long address)
  382. {
  383. unsigned long error_code;
  384. mm_segment_t oldfs;
  385. u16 instruction;
  386. int tmp;
  387. asm volatile("stc       r2_bank,%0": "=r" (error_code));
  388. oldfs = get_fs();
  389. if (user_mode(regs)) {
  390. sti();
  391. current->thread.error_code = error_code;
  392. current->thread.trap_no = (writeaccess) ? 8 : 7;
  393. /* bad PC is not something we can fix */
  394. if (regs->pc & 1)
  395. goto uspace_segv;
  396. set_fs(USER_DS);
  397. if (copy_from_user(&instruction, (u16 *)(regs->pc), 2)) {
  398. /* Argh. Fault on the instruction itself.
  399.    This should never happen non-SMP
  400. */
  401. set_fs(oldfs);
  402. goto uspace_segv;
  403. }
  404. tmp = handle_unaligned_access(instruction, regs);
  405. set_fs(oldfs);
  406. if (tmp==0)
  407. return; /* sorted */
  408. uspace_segv:
  409. printk(KERN_NOTICE "Killing process "%s" due to unaligned accessn", current->comm);
  410. force_sig(SIGSEGV, current);
  411. } else {
  412. if (regs->pc & 1)
  413. die("unaligned program counter", regs, error_code);
  414. set_fs(KERNEL_DS);
  415. if (copy_from_user(&instruction, (u16 *)(regs->pc), 2)) {
  416. /* Argh. Fault on the instruction itself.
  417.    This should never happen non-SMP
  418. */
  419. set_fs(oldfs);
  420. die("insn faulting in do_address_error", regs, 0);
  421. }
  422. handle_unaligned_access(instruction, regs);
  423. set_fs(oldfs);
  424. }
  425. }
  426. DO_ERROR(12, SIGILL,  "reserved instruction", reserved_inst, current)
  427. DO_ERROR(13, SIGILL,  "illegal slot instruction", illegal_slot_inst, current)
  428. asmlinkage void do_exception_error(unsigned long r4, unsigned long r5,
  429.    unsigned long r6, unsigned long r7,
  430.    struct pt_regs regs)
  431. {
  432. long ex;
  433. asm volatile("stc r2_bank, %0" : "=r" (ex));
  434. die_if_kernel("exception", &regs, ex);
  435. }
  436. #if defined(CONFIG_SH_STANDARD_BIOS)
  437. void *gdb_vbr_vector;
  438. #endif
  439. void __init trap_init(void)
  440. {
  441. extern void *vbr_base;
  442. extern void *exception_handling_table[14];
  443. exception_handling_table[12] = (void *)do_reserved_inst;
  444. exception_handling_table[13] = (void *)do_illegal_slot_inst;
  445. #if defined(CONFIG_SH_STANDARD_BIOS)
  446.      /*
  447.  * Read the old value of the VBR register to initialise
  448.  * the vector through which debug and BIOS traps are
  449.  * delegated by the Linux trap handler.
  450.  */
  451. {
  452.     register unsigned long vbr;
  453.     asm volatile("stc vbr, %0" : "=r" (vbr));
  454.     gdb_vbr_vector = (void *)(vbr + 0x100);
  455.     printk("Setting GDB trap vector to 0x%08lxn",
  456.      (unsigned long)gdb_vbr_vector);
  457. }
  458. #endif
  459. /* NOTE: The VBR value should be at P1
  460.    (or P2, virtural "fixed" address space).
  461.    It's definitely should not in physical address.  */
  462. asm volatile("ldc %0, vbr"
  463.      : /* no output */
  464.      : "r" (&vbr_base)
  465.      : "memory");
  466. }
  467. void dump_stack(void)
  468. {
  469. unsigned long *start;
  470. unsigned long *end;
  471. unsigned long *p;
  472. asm("mov r15, %0" : "=r" (start));
  473. asm("stc r7_bank, %0" : "=r" (end));
  474. end += 8192/4;
  475. printk("%08lx:%08lxn", (unsigned long)start, (unsigned long)end);
  476. for (p=start; p < end; p++) {
  477. extern long _text, _etext;
  478. unsigned long v=*p;
  479. if ((v >= (unsigned long )&_text)
  480.     && (v <= (unsigned long )&_etext)) {
  481. printk("%08lxn", v);
  482. }
  483. }
  484. }
  485. void show_trace_task(struct task_struct *tsk)
  486. {
  487. printk("Backtrace not yet implemented for SH.n");
  488. }