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

嵌入式Linux

开发平台:

Unix_Linux

  1. /* $Id: traps.c,v 1.64 2000/09/03 15:00:49 anton Exp $
  2.  * arch/sparc/kernel/traps.c
  3.  *
  4.  * Copyright 1995 David S. Miller (davem@caip.rutgers.edu)
  5.  * Copyright 2000 Jakub Jelinek (jakub@redhat.com)
  6.  */
  7. /*
  8.  * I hate traps on the sparc, grrr...
  9.  */
  10. #include <linux/config.h>
  11. #include <linux/sched.h>  /* for jiffies */
  12. #include <linux/kernel.h>
  13. #include <linux/signal.h>
  14. #include <linux/smp.h>
  15. #include <linux/smp_lock.h>
  16. #include <asm/delay.h>
  17. #include <asm/system.h>
  18. #include <asm/ptrace.h>
  19. #include <asm/oplib.h>
  20. #include <asm/page.h>
  21. #include <asm/pgtable.h>
  22. #include <asm/kdebug.h>
  23. #include <asm/unistd.h>
  24. #include <asm/traps.h>
  25. /* #define TRAP_DEBUG */
  26. struct trap_trace_entry {
  27. unsigned long pc;
  28. unsigned long type;
  29. };
  30. int trap_curbuf = 0;
  31. struct trap_trace_entry trapbuf[1024];
  32. void syscall_trace_entry(struct pt_regs *regs)
  33. {
  34. printk("%s[%d]: ", current->comm, current->pid);
  35. printk("scall<%d> (could be %d)n", (int) regs->u_regs[UREG_G1],
  36.        (int) regs->u_regs[UREG_I0]);
  37. }
  38. void syscall_trace_exit(struct pt_regs *regs)
  39. {
  40. }
  41. void sun4m_nmi(struct pt_regs *regs)
  42. {
  43. unsigned long afsr, afar;
  44. printk("Aieee: sun4m NMI received!n");
  45. /* XXX HyperSparc hack XXX */
  46. __asm__ __volatile__("mov 0x500, %%g1nt"
  47.      "lda [%%g1] 0x4, %0nt"
  48.      "mov 0x600, %%g1nt"
  49.      "lda [%%g1] 0x4, %1nt" :
  50.      "=r" (afsr), "=r" (afar));
  51. printk("afsr=%08lx afar=%08lxn", afsr, afar);
  52. printk("you lose buddy boy...n");
  53. show_regs(regs);
  54. prom_halt();
  55. }
  56. void sun4d_nmi(struct pt_regs *regs)
  57. {
  58. printk("Aieee: sun4d NMI received!n");
  59. printk("you lose buddy boy...n");
  60. show_regs(regs);
  61. prom_halt();
  62. }
  63. void instruction_dump (unsigned long *pc)
  64. {
  65. int i;
  66. if((((unsigned long) pc) & 3))
  67.                 return;
  68. for(i = -3; i < 6; i++)
  69. printk("%c%08lx%c",i?' ':'<',pc[i],i?' ':'>');
  70. printk("n");
  71. }
  72. #define __SAVE __asm__ __volatile__("save %sp, -0x40, %spnt")
  73. #define __RESTORE __asm__ __volatile__("restore %g0, %g0, %g0nt")
  74. void die_if_kernel(char *str, struct pt_regs *regs)
  75. {
  76. int count = 0;
  77. /* Amuse the user. */
  78. printk(
  79. "              \|/ ____ \|/n"
  80. "              "@'/ ,. \`@"n"
  81. "              /_| \__/ |_\n"
  82. "                 \__U_/n");
  83. printk("%s(%d): %sn", current->comm, current->pid, str);
  84. show_regs(regs);
  85. __SAVE; __SAVE; __SAVE; __SAVE;
  86. __SAVE; __SAVE; __SAVE; __SAVE;
  87. __RESTORE; __RESTORE; __RESTORE; __RESTORE;
  88. __RESTORE; __RESTORE; __RESTORE; __RESTORE;
  89. {
  90. struct reg_window *rw = (struct reg_window *)regs->u_regs[UREG_FP];
  91. /* Stop the back trace when we hit userland or we
  92.  * find some badly aligned kernel stack. Set an upper
  93.  * bound in case our stack is trashed and we loop.
  94.  */
  95. while(rw &&
  96.       count++ < 30 &&
  97.                       (((unsigned long) rw) >= PAGE_OFFSET) &&
  98.       !(((unsigned long) rw) & 0x7)) {
  99. printk("Caller[%08lx]n", rw->ins[7]);
  100. rw = (struct reg_window *)rw->ins[6];
  101. }
  102. }
  103. printk("Instruction DUMP:");
  104. instruction_dump ((unsigned long *) regs->pc);
  105. if(regs->psr & PSR_PS)
  106. do_exit(SIGKILL);
  107. do_exit(SIGSEGV);
  108. }
  109. void do_hw_interrupt(unsigned long type, unsigned long psr, unsigned long pc)
  110. {
  111. siginfo_t info;
  112. if(type < 0x80) {
  113. /* Sun OS's puke from bad traps, Linux survives! */
  114. printk("Unimplemented Sparc TRAP, type = %02lxn", type);
  115. die_if_kernel("Whee... Hello Mr. Penguin", current->thread.kregs);
  116. }
  117. if(psr & PSR_PS)
  118. die_if_kernel("Kernel bad trap", current->thread.kregs);
  119. info.si_signo = SIGILL;
  120. info.si_errno = 0;
  121. info.si_code = ILL_ILLTRP;
  122. info.si_addr = (void *)pc;
  123. info.si_trapno = type - 0x80;
  124. force_sig_info(SIGILL, &info, current);
  125. }
  126. void do_illegal_instruction(struct pt_regs *regs, unsigned long pc, unsigned long npc,
  127.     unsigned long psr)
  128. {
  129. siginfo_t info;
  130. if(psr & PSR_PS)
  131. die_if_kernel("Kernel illegal instruction", regs);
  132. #ifdef TRAP_DEBUG
  133. printk("Ill instr. at pc=%08lx instruction is %08lxn",
  134.        regs->pc, *(unsigned long *)regs->pc);
  135. #endif
  136. if (sparc_cpu_model == sun4c || sparc_cpu_model == sun4) {
  137. extern int do_user_muldiv (struct pt_regs *, unsigned long);
  138. if (!do_user_muldiv (regs, pc))
  139. return;
  140. }
  141. info.si_signo = SIGILL;
  142. info.si_errno = 0;
  143. info.si_code = ILL_ILLOPC;
  144. info.si_addr = (void *)pc;
  145. info.si_trapno = 0;
  146. send_sig_info(SIGILL, &info, current);
  147. }
  148. void do_priv_instruction(struct pt_regs *regs, unsigned long pc, unsigned long npc,
  149.  unsigned long psr)
  150. {
  151. siginfo_t info;
  152. if(psr & PSR_PS)
  153. die_if_kernel("Penguin instruction from Penguin mode??!?!", regs);
  154. info.si_signo = SIGILL;
  155. info.si_errno = 0;
  156. info.si_code = ILL_PRVOPC;
  157. info.si_addr = (void *)pc;
  158. info.si_trapno = 0;
  159. send_sig_info(SIGILL, &info, current);
  160. }
  161. /* XXX User may want to be allowed to do this. XXX */
  162. void do_memaccess_unaligned(struct pt_regs *regs, unsigned long pc, unsigned long npc,
  163.     unsigned long psr)
  164. {
  165. siginfo_t info;
  166. if(regs->psr & PSR_PS) {
  167. printk("KERNEL MNA at pc %08lx npc %08lx called by %08lxn", pc, npc,
  168.        regs->u_regs[UREG_RETPC]);
  169. die_if_kernel("BOGUS", regs);
  170. /* die_if_kernel("Kernel MNA access", regs); */
  171. }
  172. #if 0
  173. show_regs (regs);
  174. instruction_dump ((unsigned long *) regs->pc);
  175. printk ("do_MNA!n");
  176. #endif
  177. info.si_signo = SIGBUS;
  178. info.si_errno = 0;
  179. info.si_code = BUS_ADRALN;
  180. info.si_addr = /* FIXME: Should dig out mna address */ (void *)0;
  181. info.si_trapno = 0;
  182. send_sig_info(SIGBUS, &info, current);
  183. }
  184. extern void fpsave(unsigned long *fpregs, unsigned long *fsr,
  185.    void *fpqueue, unsigned long *fpqdepth);
  186. extern void fpload(unsigned long *fpregs, unsigned long *fsr);
  187. static unsigned long init_fsr = 0x0UL;
  188. static unsigned long init_fregs[32] __attribute__ ((aligned (8))) =
  189.                 { ~0UL, ~0UL, ~0UL, ~0UL, ~0UL, ~0UL, ~0UL, ~0UL,
  190.   ~0UL, ~0UL, ~0UL, ~0UL, ~0UL, ~0UL, ~0UL, ~0UL,
  191.   ~0UL, ~0UL, ~0UL, ~0UL, ~0UL, ~0UL, ~0UL, ~0UL,
  192.   ~0UL, ~0UL, ~0UL, ~0UL, ~0UL, ~0UL, ~0UL, ~0UL };
  193. void do_fpd_trap(struct pt_regs *regs, unsigned long pc, unsigned long npc,
  194.  unsigned long psr)
  195. {
  196. /* Sanity check... */
  197. if(psr & PSR_PS)
  198. die_if_kernel("Kernel gets FloatingPenguinUnit disabled trap", regs);
  199. put_psr(get_psr() | PSR_EF);    /* Allow FPU ops. */
  200. regs->psr |= PSR_EF;
  201. #ifndef CONFIG_SMP
  202. if(last_task_used_math == current)
  203. return;
  204. if(last_task_used_math) {
  205. /* Other processes fpu state, save away */
  206. struct task_struct *fptask = last_task_used_math;
  207. fpsave(&fptask->thread.float_regs[0], &fptask->thread.fsr,
  208.        &fptask->thread.fpqueue[0], &fptask->thread.fpqdepth);
  209. }
  210. last_task_used_math = current;
  211. if(current->used_math) {
  212. fpload(&current->thread.float_regs[0], &current->thread.fsr);
  213. } else {
  214. /* Set initial sane state. */
  215. fpload(&init_fregs[0], &init_fsr);
  216. current->used_math = 1;
  217. }
  218. #else
  219. if(!current->used_math) {
  220. fpload(&init_fregs[0], &init_fsr);
  221. current->used_math = 1;
  222. } else {
  223. fpload(&current->thread.float_regs[0], &current->thread.fsr);
  224. }
  225. current->flags |= PF_USEDFPU;
  226. #endif
  227. }
  228. static unsigned long fake_regs[32] __attribute__ ((aligned (8)));
  229. static unsigned long fake_fsr;
  230. static unsigned long fake_queue[32] __attribute__ ((aligned (8)));
  231. static unsigned long fake_depth;
  232. extern int do_mathemu(struct pt_regs *, struct task_struct *);
  233. void do_fpe_trap(struct pt_regs *regs, unsigned long pc, unsigned long npc,
  234.  unsigned long psr)
  235. {
  236. static int calls = 0;
  237. siginfo_t info;
  238. unsigned long fsr;
  239. int ret = 0;
  240. #ifndef CONFIG_SMP
  241. struct task_struct *fpt = last_task_used_math;
  242. #else
  243. struct task_struct *fpt = current;
  244. #endif
  245. put_psr(get_psr() | PSR_EF);
  246. /* If nobody owns the fpu right now, just clear the
  247.  * error into our fake static buffer and hope it don't
  248.  * happen again.  Thank you crashme...
  249.  */
  250. #ifndef CONFIG_SMP
  251. if(!fpt) {
  252. #else
  253.         if(!(fpt->flags & PF_USEDFPU)) {
  254. #endif
  255. fpsave(&fake_regs[0], &fake_fsr, &fake_queue[0], &fake_depth);
  256. regs->psr &= ~PSR_EF;
  257. return;
  258. }
  259. fpsave(&fpt->thread.float_regs[0], &fpt->thread.fsr,
  260.        &fpt->thread.fpqueue[0], &fpt->thread.fpqdepth);
  261. #ifdef DEBUG_FPU
  262. printk("Hmm, FP exception, fsr was %016lxn", fpt->thread.fsr);
  263. #endif
  264. switch ((fpt->thread.fsr & 0x1c000)) {
  265. /* switch on the contents of the ftt [floating point trap type] field */
  266. #ifdef DEBUG_FPU
  267. case (1 << 14):
  268. printk("IEEE_754_exceptionn");
  269. break;
  270. #endif
  271. case (2 << 14):  /* unfinished_FPop (underflow & co) */
  272. case (3 << 14):  /* unimplemented_FPop (quad stuff, maybe sqrt) */
  273. ret = do_mathemu(regs, fpt);
  274. break;
  275. #ifdef DEBUG_FPU
  276. case (4 << 14):
  277. printk("sequence_error (OS bug...)n");
  278. break;
  279. case (5 << 14):
  280. printk("hardware_error (uhoh!)n");
  281. break;
  282. case (6 << 14):
  283. printk("invalid_fp_register (user error)n");
  284. break;
  285. #endif /* DEBUG_FPU */
  286. }
  287. /* If we successfully emulated the FPop, we pretend the trap never happened :-> */
  288. if (ret) {
  289. fpload(&current->thread.float_regs[0], &current->thread.fsr);
  290. return;
  291. }
  292. /* nope, better SIGFPE the offending process... */
  293.        
  294. #ifdef CONFIG_SMP
  295. fpt->flags &= ~PF_USEDFPU;
  296. #endif
  297. if(psr & PSR_PS) {
  298. /* The first fsr store/load we tried trapped,
  299.  * the second one will not (we hope).
  300.  */
  301. printk("WARNING: FPU exception from kernel mode. at pc=%08lxn",
  302.        regs->pc);
  303. regs->pc = regs->npc;
  304. regs->npc += 4;
  305. calls++;
  306. if(calls > 2)
  307. die_if_kernel("Too many Penguin-FPU traps from kernel mode",
  308.       regs);
  309. return;
  310. }
  311. fsr = fpt->thread.fsr;
  312. info.si_signo = SIGFPE;
  313. info.si_errno = 0;
  314. info.si_addr = (void *)pc;
  315. info.si_trapno = 0;
  316. info.si_code = __SI_FAULT;
  317. if ((fsr & 0x1c000) == (1 << 14)) {
  318. if (fsr & 0x10)
  319. info.si_code = FPE_FLTINV;
  320. else if (fsr & 0x08)
  321. info.si_code = FPE_FLTOVF;
  322. else if (fsr & 0x04)
  323. info.si_code = FPE_FLTUND;
  324. else if (fsr & 0x02)
  325. info.si_code = FPE_FLTDIV;
  326. else if (fsr & 0x01)
  327. info.si_code = FPE_FLTRES;
  328. }
  329. send_sig_info(SIGFPE, &info, fpt);
  330. #ifndef CONFIG_SMP
  331. last_task_used_math = NULL;
  332. #endif
  333. regs->psr &= ~PSR_EF;
  334. if(calls > 0)
  335. calls=0;
  336. }
  337. void handle_tag_overflow(struct pt_regs *regs, unsigned long pc, unsigned long npc,
  338.  unsigned long psr)
  339. {
  340. siginfo_t info;
  341. if(psr & PSR_PS)
  342. die_if_kernel("Penguin overflow trap from kernel mode", regs);
  343. info.si_signo = SIGEMT;
  344. info.si_errno = 0;
  345. info.si_code = EMT_TAGOVF;
  346. info.si_addr = (void *)pc;
  347. info.si_trapno = 0;
  348. send_sig_info(SIGEMT, &info, current);
  349. }
  350. void handle_watchpoint(struct pt_regs *regs, unsigned long pc, unsigned long npc,
  351.        unsigned long psr)
  352. {
  353. #ifdef TRAP_DEBUG
  354. printk("Watchpoint detected at PC %08lx NPC %08lx PSR %08lxn",
  355.        pc, npc, psr);
  356. #endif
  357. if(psr & PSR_PS)
  358. panic("Tell me what a watchpoint trap is, and I'll then deal "
  359.       "with such a beast...");
  360. }
  361. void handle_reg_access(struct pt_regs *regs, unsigned long pc, unsigned long npc,
  362.        unsigned long psr)
  363. {
  364. siginfo_t info;
  365. #ifdef TRAP_DEBUG
  366. printk("Register Access Exception at PC %08lx NPC %08lx PSR %08lxn",
  367.        pc, npc, psr);
  368. #endif
  369. info.si_signo = SIGBUS;
  370. info.si_errno = 0;
  371. info.si_code = BUS_OBJERR;
  372. info.si_addr = (void *)pc;
  373. info.si_trapno = 0;
  374. force_sig_info(SIGBUS, &info, current);
  375. }
  376. void handle_cp_disabled(struct pt_regs *regs, unsigned long pc, unsigned long npc,
  377. unsigned long psr)
  378. {
  379. siginfo_t info;
  380. info.si_signo = SIGILL;
  381. info.si_errno = 0;
  382. info.si_code = ILL_COPROC;
  383. info.si_addr = (void *)pc;
  384. info.si_trapno = 0;
  385. send_sig_info(SIGILL, &info, current);
  386. }
  387. void handle_cp_exception(struct pt_regs *regs, unsigned long pc, unsigned long npc,
  388.  unsigned long psr)
  389. {
  390. siginfo_t info;
  391. #ifdef TRAP_DEBUG
  392. printk("Co-Processor Exception at PC %08lx NPC %08lx PSR %08lxn",
  393.        pc, npc, psr);
  394. #endif
  395. info.si_signo = SIGILL;
  396. info.si_errno = 0;
  397. info.si_code = ILL_COPROC;
  398. info.si_addr = (void *)pc;
  399. info.si_trapno = 0;
  400. send_sig_info(SIGILL, &info, current);
  401. }
  402. void handle_hw_divzero(struct pt_regs *regs, unsigned long pc, unsigned long npc,
  403.        unsigned long psr)
  404. {
  405. siginfo_t info;
  406. info.si_signo = SIGFPE;
  407. info.si_errno = 0;
  408. info.si_code = FPE_INTDIV;
  409. info.si_addr = (void *)pc;
  410. info.si_trapno = 0;
  411. send_sig_info(SIGFPE, &info, current);
  412. }
  413. /* Since we have our mappings set up, on multiprocessors we can spin them
  414.  * up here so that timer interrupts work during initialization.
  415.  */
  416. extern void sparc_cpu_startup(void);
  417. int linux_smp_still_initting;
  418. unsigned int thiscpus_tbr;
  419. int thiscpus_mid;
  420. void trap_init(void)
  421. {
  422. /* Attach to the address space of init_task. */
  423. atomic_inc(&init_mm.mm_count);
  424. current->active_mm = &init_mm;
  425. /* NOTE: Other cpus have this done as they are started
  426.  *       up on SMP.
  427.  */
  428. }