traps.c
上传用户:jlfgdled
上传日期:2013-04-10
资源大小:33168k
文件大小:8k
源码类别:

Linux/Unix编程

开发平台:

Unix_Linux

  1. /*
  2.  *  linux/arch/ppc/kernel/traps.c
  3.  *
  4.  *  Copyright (C) 1995-1996  Gary Thomas (gdt@linuxppc.org)
  5.  *
  6.  *  This program is free software; you can redistribute it and/or
  7.  *  modify it under the terms of the GNU General Public License
  8.  *  as published by the Free Software Foundation; either version
  9.  *  2 of the License, or (at your option) any later version.
  10.  *
  11.  *  Modified by Cort Dougan (cort@cs.nmt.edu)
  12.  *  and Paul Mackerras (paulus@cs.anu.edu.au)
  13.  */
  14. /*
  15.  * This file handles the architecture-dependent parts of hardware exceptions
  16.  */
  17. #include <linux/errno.h>
  18. #include <linux/sched.h>
  19. #include <linux/kernel.h>
  20. #include <linux/mm.h>
  21. #include <linux/stddef.h>
  22. #include <linux/unistd.h>
  23. #include <linux/ptrace.h>
  24. #include <linux/slab.h>
  25. #include <linux/user.h>
  26. #include <linux/a.out.h>
  27. #include <linux/interrupt.h>
  28. #include <linux/config.h>
  29. #include <linux/init.h>
  30. #include <asm/iSeries/HvCall.h>
  31. #include <asm/iSeries/HvCallCfg.h>
  32. #ifdef CONFIG_KDB
  33. #include <linux/kdb.h>
  34. #endif
  35. #include <asm/pgtable.h>
  36. #include <asm/uaccess.h>
  37. #include <asm/system.h>
  38. #include <asm/io.h>
  39. #include <asm/processor.h>
  40. #include <asm/ppcdebug.h>
  41. extern int fix_alignment(struct pt_regs *);
  42. extern void bad_page_fault(struct pt_regs *, unsigned long);
  43. /* This is true if we are using the firmware NMI handler (typically LPAR) */
  44. extern int fwnmi_active;
  45. #ifdef CONFIG_XMON
  46. extern void xmon(struct pt_regs *regs);
  47. extern int xmon_bpt(struct pt_regs *regs);
  48. extern int xmon_sstep(struct pt_regs *regs);
  49. extern int xmon_iabr_match(struct pt_regs *regs);
  50. extern int xmon_dabr_match(struct pt_regs *regs);
  51. extern void (*xmon_fault_handler)(struct pt_regs *regs);
  52. #endif
  53. #ifdef CONFIG_XMON
  54. void (*debugger)(struct pt_regs *regs) = xmon;
  55. int (*debugger_bpt)(struct pt_regs *regs) = xmon_bpt;
  56. int (*debugger_sstep)(struct pt_regs *regs) = xmon_sstep;
  57. int (*debugger_iabr_match)(struct pt_regs *regs) = xmon_iabr_match;
  58. int (*debugger_dabr_match)(struct pt_regs *regs) = xmon_dabr_match;
  59. void (*debugger_fault_handler)(struct pt_regs *regs);
  60. #else
  61. #ifdef CONFIG_KGDB
  62. void (*debugger)(struct pt_regs *regs);
  63. int (*debugger_bpt)(struct pt_regs *regs);
  64. int (*debugger_sstep)(struct pt_regs *regs);
  65. int (*debugger_iabr_match)(struct pt_regs *regs);
  66. int (*debugger_dabr_match)(struct pt_regs *regs);
  67. void (*debugger_fault_handler)(struct pt_regs *regs);
  68. #else
  69. #ifdef CONFIG_KDB
  70. /* kdb has different call parms */
  71. /* ... */
  72. void (*debugger)(struct pt_regs *regs) = kdb;
  73. int (*debugger_bpt)(struct pt_regs *regs);
  74. int (*debugger_sstep)(struct pt_regs *regs);
  75. int (*debugger_iabr_match)(struct pt_regs *regs);
  76. int (*debugger_dabr_match)(struct pt_regs *regs);
  77. /* - only defined during (xmon) mread */
  78. void (*debugger_fault_handler)(struct pt_regs *regs);
  79. #endif /* kdb */
  80. #endif /* kgdb */
  81. #endif /* xmon */
  82. void set_local_DABR(void *valp);
  83. /*
  84.  * Trap & Exception support
  85.  */
  86. void
  87. _exception(int signr, struct pt_regs *regs)
  88. {
  89. if (!user_mode(regs))
  90. {
  91. show_regs(regs);
  92. #if defined(CONFIG_XMON) || defined(CONFIG_KGDB)
  93. debugger(regs);
  94. #endif
  95. #if defined(CONFIG_KDB)
  96. kdb(KDB_REASON_OOPS, 0, (kdb_eframe_t) regs);
  97. #endif
  98. print_backtrace((unsigned long *)regs->gpr[1]);
  99. panic("Exception in kernel pc %lx signal %d",regs->nip,signr);
  100. #if defined(CONFIG_PPCDBG) && (defined(CONFIG_XMON) || defined(CONFIG_KGDB))
  101. /* Allow us to catch SIGILLs for 64-bit app/glibc debugging. -Peter */
  102. } else if (signr == SIGILL) {
  103. ifppcdebug(PPCDBG_SIGNALXMON)
  104. debugger(regs);
  105. #endif
  106. }
  107. force_sig(signr, current);
  108. }
  109. /* Get the error information for errors coming through the
  110.  * FWNMI vectors.  The pt_regs' r3 will be updated to reflect
  111.  * the actual r3 if possible, and a ptr to the error log entry
  112.  * will be returned if found.
  113.  */
  114. static struct rtas_error_log *FWNMI_get_errinfo(struct pt_regs *regs)
  115. {
  116. unsigned long errdata = regs->gpr[3];
  117. struct rtas_error_log *errhdr = NULL;
  118. unsigned long *savep;
  119. if ((errdata >= 0x7000 && errdata < 0x7fff0) ||
  120.     (errdata >= rtas.base && errdata < rtas.base + rtas.size - 16)) {
  121. savep = __va(errdata);
  122. regs->gpr[3] = savep[0]; /* restore original r3 */
  123. errhdr = (struct rtas_error_log *)(savep + 1);
  124. } else {
  125. printk("FWNMI: corrupt r3n");
  126. }
  127. return errhdr;
  128. }
  129. /* Call this when done with the data returned by FWNMI_get_errinfo.
  130.  * It will release the saved data area for other CPUs in the
  131.  * partition to receive FWNMI errors.
  132.  */
  133. static void FWNMI_release_errinfo(void)
  134. {
  135. unsigned long ret = rtas_call(rtas_token("ibm,nmi-interlock"), 0, 1, NULL);
  136. if (ret != 0)
  137. printk("FWNMI: nmi-interlock failed: %ldn", ret);
  138. }
  139. void
  140. SystemResetException(struct pt_regs *regs)
  141. {
  142. char *msg = "System Reset in kernel mode.n";
  143. udbg_printf(msg); printk(msg);
  144. if (fwnmi_active) {
  145. unsigned long *r3 = __va(regs->gpr[3]); /* for FWNMI debug */
  146. struct rtas_error_log *errlog;
  147. msg = "FWNMI is active with save area at %016lxn";
  148. udbg_printf(msg, r3); printk(msg, r3);
  149. errlog = FWNMI_get_errinfo(regs);
  150. }
  151. #if defined(CONFIG_XMON)
  152. xmon(regs);
  153. udbg_printf("leaving xmon...n");
  154. #endif
  155. #if defined(CONFIG_KDB)
  156. kdb(KDB_REASON_ENTER, regs->trap, (kdb_eframe_t) regs);
  157. udbg_printf("leaving kdb...n");
  158. #endif
  159. /*
  160. allow system to resume after reset.
  161. for(;;);
  162. */
  163. }
  164. void
  165. MachineCheckException(struct pt_regs *regs)
  166. {
  167. if (fwnmi_active) {
  168. struct rtas_error_log *errhdr = FWNMI_get_errinfo(regs);
  169. if (errhdr) {
  170. /* ToDo: attempt to recover from some errors here */
  171. }
  172. FWNMI_release_errinfo();
  173. }
  174. if ( !user_mode(regs) )
  175. {
  176. #if defined(CONFIG_XMON) || defined(CONFIG_KGDB)
  177. if (debugger_fault_handler) {
  178. debugger_fault_handler(regs);
  179. return;
  180. }
  181. #endif
  182. #ifdef CONFIG_KDB
  183. if (kdb(KDB_REASON_FAULT, 0, regs))
  184. return;
  185. #endif
  186. printk("Machine check in kernel mode.n");
  187. printk("Caused by (from SRR1=%lx): ", regs->msr);
  188. show_regs(regs);
  189. #if defined(CONFIG_XMON) || defined(CONFIG_KGDB)
  190. debugger(regs);
  191. #endif
  192. #ifdef CONFIG_KDB
  193. if (kdb(KDB_REASON_FAULT, 0, regs))
  194. return ;
  195. #endif
  196. print_backtrace((unsigned long *)regs->gpr[1]);
  197. panic("machine check");
  198. }
  199. _exception(SIGSEGV, regs);
  200. }
  201. void
  202. SMIException(struct pt_regs *regs)
  203. {
  204. #if defined(CONFIG_XMON) || defined(CONFIG_KGDB)
  205. {
  206. debugger(regs);
  207. return;
  208. }
  209. #endif
  210. #ifdef CONFIG_KDB
  211. {
  212. kdb(KDB_REASON_OOPS, 0, regs);
  213. return;
  214. }
  215. #endif
  216. show_regs(regs);
  217. print_backtrace((unsigned long *)regs->gpr[1]);
  218. panic("System Management Interrupt");
  219. }
  220. void
  221. UnknownException(struct pt_regs *regs)
  222. {
  223. printk("Bad trap at PC: %lx, SR: %lx, vector=%lxn",
  224.        regs->nip, regs->msr, regs->trap);
  225. _exception(SIGTRAP, regs);
  226. }
  227. void
  228. InstructionBreakpointException(struct pt_regs *regs)
  229. {
  230. #if defined(CONFIG_XMON) || defined(CONFIG_KGDB)
  231. if (debugger_iabr_match(regs))
  232. return;
  233. #endif
  234. #ifdef CONFIG_KDB
  235. if (kdb(KDB_REASON_BREAK, 0, regs))
  236. return ;
  237. #endif
  238. _exception(SIGTRAP, regs);
  239. }
  240. void
  241. ProgramCheckException(struct pt_regs *regs)
  242. {
  243. if (regs->msr & 0x100000) {
  244. /* IEEE FP exception */
  245. _exception(SIGFPE, regs);
  246. } else if (regs->msr & 0x20000) {
  247. /* trap exception */
  248. #if defined(CONFIG_XMON) || defined(CONFIG_KGDB)
  249. if (debugger_bpt(regs))
  250. return;
  251. #endif
  252. #ifdef CONFIG_KDB
  253. if (kdb(KDB_REASON_BREAK, 0, regs))
  254. return;
  255. #endif
  256. _exception(SIGTRAP, regs);
  257. } else {
  258. _exception(SIGILL, regs);
  259. }
  260. }
  261. void
  262. SingleStepException(struct pt_regs *regs)
  263. {
  264. regs->msr &= ~MSR_SE;  /* Turn off 'trace' bit */
  265. #if defined(CONFIG_XMON) || defined(CONFIG_KGDB)
  266. if (debugger_sstep(regs))
  267. return;
  268. #endif
  269. #ifdef CONFIG_KDB
  270. if (kdb(KDB_REASON_DEBUG, 0, regs))
  271. return;
  272. #endif
  273. _exception(SIGTRAP, regs);
  274. }
  275. void
  276. AlignmentException(struct pt_regs *regs)
  277. {
  278. int fixed;
  279. fixed = fix_alignment(regs);
  280. if (fixed == 1) {
  281. ifppcdebug(PPCDBG_ALIGNFIXUP)
  282. if (!user_mode(regs))
  283. PPCDBG(PPCDBG_ALIGNFIXUP, "fix alignment at %lxn", regs->nip);
  284. regs->nip += 4; /* skip over emulated instruction */
  285. return;
  286. }
  287. if (fixed == -EFAULT) {
  288. /* fixed == -EFAULT means the operand address was bad */
  289. if (user_mode(regs))
  290. force_sig(SIGSEGV, current);
  291. else
  292. bad_page_fault(regs, regs->dar);
  293. return;
  294. }
  295. _exception(SIGBUS, regs);
  296. }
  297. void __init trap_init(void)
  298. {
  299. }
  300. /*
  301.  * Set the DABR on all processors in the system.  The value is defined as:
  302.  * DAB(0:60), Break Translate(61), Write(62), Read(63)
  303.  */
  304. void
  305. set_all_DABR(unsigned long val) {
  306. set_local_DABR(&val); 
  307. smp_call_function(set_local_DABR, &val, 0, 0);
  308. }
  309. void
  310. set_local_DABR(void *valp) {
  311. unsigned long val = *((unsigned long *)valp); 
  312. HvCall_setDABR(val);
  313. }