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

Linux/Unix编程

开发平台:

Unix_Linux

  1. /*
  2.  *  linux/arch/x86-64/traps.c
  3.  *
  4.  *  Copyright (C) 1991, 1992  Linus Torvalds
  5.  *  Copyright (C) 2000, 2001, 2002 Andi Kleen, SuSE Labs
  6.  *
  7.  *  Pentium III FXSR, SSE support
  8.  * Gareth Hughes <gareth@valinux.com>, May 2000
  9.  *
  10.  *  $Id: traps.c,v 1.51 2002/09/12 12:57:46 ak Exp $
  11.  */
  12. /*
  13.  * 'Traps.c' handles hardware traps and faults after we have saved some
  14.  * state in 'entry.S'.
  15.  */
  16. #include <linux/config.h>
  17. #include <linux/sched.h>
  18. #include <linux/kernel.h>
  19. #include <linux/string.h>
  20. #include <linux/errno.h>
  21. #include <linux/ptrace.h>
  22. #include <linux/timer.h>
  23. #include <linux/mm.h>
  24. #include <linux/init.h>
  25. #include <linux/delay.h>
  26. #include <linux/spinlock.h>
  27. #include <linux/interrupt.h>
  28. #include <linux/module.h>
  29. #include <asm/system.h>
  30. #include <asm/uaccess.h>
  31. #include <asm/io.h>
  32. #include <asm/atomic.h>
  33. #include <asm/debugreg.h>
  34. #include <asm/desc.h>
  35. #include <asm/i387.h>
  36. #include <asm/kdebug.h>
  37. #include <asm/smp.h>
  38. #include <asm/pgalloc.h>
  39. #include <asm/pda.h>
  40. #include <asm/proto.h>
  41. #include <linux/irq.h>
  42. extern int exception_trace;
  43. extern struct gate_struct idt_table[256]; 
  44. asmlinkage void divide_error(void);
  45. asmlinkage void debug(void);
  46. asmlinkage void nmi(void);
  47. asmlinkage void int3(void);
  48. asmlinkage void overflow(void);
  49. asmlinkage void bounds(void);
  50. asmlinkage void invalid_op(void);
  51. asmlinkage void device_not_available(void);
  52. asmlinkage void double_fault(void);
  53. asmlinkage void coprocessor_segment_overrun(void);
  54. asmlinkage void invalid_TSS(void);
  55. asmlinkage void segment_not_present(void);
  56. asmlinkage void stack_segment(void);
  57. asmlinkage void general_protection(void);
  58. asmlinkage void page_fault(void);
  59. asmlinkage void coprocessor_error(void);
  60. asmlinkage void simd_coprocessor_error(void);
  61. asmlinkage void reserved(void);
  62. asmlinkage void alignment_check(void);
  63. asmlinkage void machine_check(void);
  64. asmlinkage void spurious_interrupt_bug(void);
  65. asmlinkage void call_debug(void);
  66. extern char iret_address[];
  67. struct notifier_block *die_chain;
  68. int kstack_depth_to_print = 40;
  69. #ifdef CONFIG_KALLSYMS
  70. #include <linux/kallsyms.h> 
  71. int printk_address(unsigned long address)
  72. unsigned long dummy; 
  73. const char *modname, *secname, *symname;
  74. unsigned long symstart; 
  75. char *delim = ":"; 
  76. /* What a function call! */
  77. if (!kallsyms_address_to_symbol(address, 
  78. &modname, &dummy, &dummy, 
  79. &secname, &dummy, &dummy,
  80. &symname, &symstart, &dummy)) {
  81. return printk("[<%016lx>]", address);
  82. if (!strcmp(modname, "kernel"))
  83. modname = delim = ""; 
  84.         return printk("[%016lx%s%s%s%s%+ld]",
  85.       address,delim,modname,delim,symname,address-symstart); 
  86. #else
  87. int printk_address(unsigned long address)
  88. return printk("[<%016lx>]", address);
  89. #endif
  90. #ifdef CONFIG_MODULES
  91. extern struct module *module_list;
  92. extern struct module kernel_module;
  93. static inline int kernel_text_address(unsigned long addr)
  94. {
  95.    int retval = 0;
  96.    struct module *mod;
  97.    if (addr >= (unsigned long) &_stext &&
  98.        addr <= (unsigned long) &_etext)
  99.        return 1;
  100.    for (mod = module_list; mod != &kernel_module; mod = mod->next) {
  101.        /* mod_bound tests for addr being inside the vmalloc'ed
  102.         * module area. Of course it'd be better to test only
  103.         * for the .text subset... */
  104.        if (mod_bound(addr, 0, mod)) {
  105.            retval = 1;
  106.            break;
  107.        }
  108.    }
  109.    return retval;
  110. }
  111. #else
  112. static inline int kernel_text_address(unsigned long addr)
  113. {
  114.    return (addr >= (unsigned long) &_stext &&
  115.        addr <= (unsigned long) &_etext);
  116. }
  117. #endif
  118. static inline unsigned long *in_exception_stack(int cpu, unsigned long stack) 
  119. int k;
  120. for (k = 0; k < N_EXCEPTION_STACKS; k++) {
  121. unsigned long end = init_tss[cpu].ist[k] + EXCEPTION_STKSZ; 
  122. if (stack >= init_tss[cpu].ist[k]  && stack <= end) 
  123. return (unsigned long *)end;
  124. }
  125. return 0;
  126. void show_trace(unsigned long *stack)
  127. {
  128. unsigned long addr;
  129. unsigned long *irqstack, *irqstack_end, *estack_end;
  130. /* FIXME: should read the cpuid from the APIC; to still work with bogus %gs */
  131. const int cpu = smp_processor_id();
  132. int i;
  133. printk("nCall Trace: ");
  134. i = 1;
  135. estack_end = in_exception_stack(cpu, (unsigned long)stack); 
  136. if (estack_end) { 
  137. while (stack < estack_end) { 
  138. addr = *stack++; 
  139. if (kernel_text_address(addr)) {  
  140. i += printk_address(addr);
  141. i += printk(" "); 
  142. if (i > 50) { 
  143. printk("n       ");
  144. i = 0;
  145. }
  146. }
  147. printk(" <EOE> "); 
  148. i += 7;
  149. stack = (unsigned long *) estack_end[-2]; 
  150. }  
  151. irqstack_end = (unsigned long *) (cpu_pda[cpu].irqstackptr);
  152. irqstack = (unsigned long *) (cpu_pda[cpu].irqstackptr - IRQSTACKSIZE + 8);
  153. if (stack >= irqstack && stack < irqstack_end) {
  154. while (stack < irqstack_end) {
  155. addr = *stack++;
  156. /*
  157.  * If the address is either in the text segment of the
  158.  * kernel, or in the region which contains vmalloc'ed
  159.  * memory, it *may* be the address of a calling
  160.  * routine; if so, print it so that someone tracing
  161.  * down the cause of the crash will be able to figure
  162.  * out the call path that was taken.
  163.  */
  164.  if (kernel_text_address(addr)) {  
  165.  i += printk_address(addr);
  166.  i += printk(" "); 
  167.  if (i > 50) { 
  168.  printk("n       ");
  169.  i = 0;
  170.  } 
  171.  }
  172. stack = (unsigned long *) (irqstack_end[-1]);
  173. i += 7; 
  174. printk(" <EOI> ");
  175. while (((long) stack & (THREAD_SIZE-1)) != 0) {
  176. addr = *stack++;
  177. if (kernel_text_address(addr)) {  
  178. i += printk_address(addr);
  179. i += printk(" "); 
  180. if (i > 50) { 
  181. printk("n       ");
  182. i = 0;
  183. }
  184. }
  185. printk("n");
  186. }
  187. void show_trace_task(struct task_struct *tsk)
  188. {
  189. unsigned long rsp = tsk->thread.rsp;
  190. /* User space on another CPU? */
  191. if ((rsp ^ (unsigned long)tsk) & (PAGE_MASK<<1))
  192. return;
  193. show_trace((unsigned long *)rsp);
  194. }
  195. void show_stack(unsigned long * rsp)
  196. {
  197. unsigned long *stack;
  198. int i;
  199. const int cpu = smp_processor_id();
  200. unsigned long *irqstack_end = (unsigned long *) (cpu_pda[cpu].irqstackptr);
  201. unsigned long *irqstack = (unsigned long *) (cpu_pda[cpu].irqstackptr - IRQSTACKSIZE);    
  202. // debugging aid: "show_stack(NULL);" prints the
  203. // back trace for this cpu.
  204. if(rsp==NULL)
  205. rsp=(unsigned long*)&rsp;
  206. stack = rsp;
  207. for(i=0; i < kstack_depth_to_print; i++) {
  208. if (stack >= irqstack && stack <= irqstack_end) {
  209. if (stack == irqstack_end) {
  210. stack = (unsigned long *) (irqstack_end[-1]);
  211. printk(" <EOI> ");
  212. }
  213. } else {
  214. if (((long) stack & (THREAD_SIZE-1)) == 0)
  215. break;
  216. }
  217. if (i && ((i % 4) == 0))
  218. printk("n       ");
  219. printk("%016lx ", *stack++);
  220. }
  221. show_trace((unsigned long *)rsp);
  222. }
  223. void dump_stack(void)
  224. {
  225. show_stack(0);
  226. void show_registers(struct pt_regs *regs)
  227. {
  228. int i;
  229. int in_kernel = 1;
  230. unsigned long rsp;
  231. #ifdef CONFIG_SMP
  232. /* For SMP should get the APIC id here, just to protect against corrupted GS */ 
  233. const int cpu = smp_processor_id(); 
  234. #else
  235. const int cpu = 0;
  236. #endif
  237. struct task_struct *cur = cpu_pda[cpu].pcurrent; 
  238. rsp = (unsigned long) (&regs->rsp);
  239. if (regs->rsp < TASK_SIZE) {
  240. in_kernel = 0;
  241. rsp = regs->rsp;
  242. }
  243. printk("CPU %d ", cpu);
  244. show_regs(regs);
  245. printk("Process %s (pid: %d, stackpage=%08lx)n",
  246. cur->comm, cur->pid, 4096+(unsigned long)cur);
  247. /*
  248.  * When in-kernel, we also print out the stack and code at the
  249.  * time of the fault..
  250.  */
  251. if (in_kernel) {
  252. printk("Stack: ");
  253. show_stack((unsigned long*)rsp);
  254. printk("nCode: ");
  255. if(regs->rip < PAGE_OFFSET)
  256. goto bad;
  257. for(i=0;i<20;i++)
  258. {
  259. unsigned char c;
  260. if(__get_user(c, &((unsigned char*)regs->rip)[i])) {
  261. bad:
  262. printk(" Bad RIP value.");
  263. break;
  264. }
  265. printk("%02x ", c);
  266. }
  267. }
  268. printk("n");
  269. }
  270. void handle_BUG(struct pt_regs *regs)
  271. struct bug_frame f;
  272. char tmp;
  273. if (regs->cs & 3)
  274. return; 
  275. if (__copy_from_user(&f, (struct bug_frame *) regs->rip, 
  276.      sizeof(struct bug_frame)))
  277. return; 
  278. if ((unsigned long)f.filename < __PAGE_OFFSET || 
  279.     f.ud2[0] != 0x0f || f.ud2[1] != 0x0b) 
  280. return;
  281. if (__get_user(tmp, f.filename))
  282. f.filename = "unmapped filename"; 
  283. printk(KERN_EMERG "Kernel BUG at %.50s:%dn", f.filename, f.line); 
  284. spinlock_t die_lock = SPIN_LOCK_UNLOCKED;
  285. int die_owner = -1;
  286. void die(const char * str, struct pt_regs * regs, long err)
  287. {
  288. int cpu;
  289. struct die_args args = { regs, str, err };
  290. console_verbose();
  291. notifier_call_chain(&die_chain,  DIE_DIE, &args); 
  292. bust_spinlocks(1);
  293. handle_BUG(regs);
  294. printk(KERN_EMERG "%s: %04lxn", str, err & 0xffff);
  295. cpu = smp_processor_id(); 
  296. /* racy, but better than risking deadlock. */ 
  297. __cli();
  298. if (!spin_trylock(&die_lock)) { 
  299. if (cpu == die_owner) 
  300. /* nested oops. should stop eventually */;
  301. else
  302. spin_lock(&die_lock); 
  303. }
  304. die_owner = cpu; 
  305. show_registers(regs);
  306. bust_spinlocks(0);
  307. spin_unlock_irq(&die_lock);
  308. notify_die(DIE_OOPS, (char *)str, regs, err);
  309. do_exit(SIGSEGV);
  310. }
  311. static inline void die_if_kernel(const char * str, struct pt_regs * regs, long err)
  312. {
  313. if (regs->cs == __KERNEL_CS)
  314. die(str, regs, err);
  315. }
  316. static inline unsigned long get_cr2(void)
  317. {
  318. unsigned long address;
  319. /* get the address */
  320. __asm__("movq %%cr2,%0":"=r" (address));
  321. return address;
  322. }
  323. static void do_trap(int trapnr, int signr, char *str, 
  324.     struct pt_regs * regs, long error_code, siginfo_t *info)
  325. {
  326. #if defined(CONFIG_CHECKING) && defined(CONFIG_LOCAL_APIC)
  327. unsigned long gs; 
  328. struct x8664_pda *pda = cpu_pda + hard_smp_processor_id(); 
  329. rdmsrl(MSR_GS_BASE, gs); 
  330. if (gs != (unsigned long)pda) { 
  331. wrmsrl(MSR_GS_BASE, pda); 
  332. printk("%s: wrong gs %lx expected %pn", str, gs, pda);
  333. }
  334. }
  335. #endif
  336. if ((regs->cs & 3)  != 0) { 
  337. struct task_struct *tsk = current;
  338. tsk->thread.error_code = error_code;
  339. tsk->thread.trap_no = trapnr;
  340. if (exception_trace)
  341. printk("%s[%d] trap %s rip:%lx rsp:%lx error:%lxn",
  342.        tsk->comm, tsk->pid, str,
  343.        regs->rip,regs->rsp,error_code); 
  344. if (info)
  345. force_sig_info(signr, info, tsk);
  346. else
  347. force_sig(signr, tsk);
  348. return;
  349. }
  350. /* kernel trap */ 
  351. {      
  352. unsigned long fixup = search_exception_table(regs->rip);
  353. if (fixup) {
  354. extern int exception_trace; 
  355. if (0 && exception_trace)
  356.        printk(KERN_ERR
  357.              "%s: fixed kernel exception at %lx err:%ldn",
  358.              current->comm, regs->rip, error_code);
  359. regs->rip = fixup;
  360. } else
  361. die(str, regs, error_code);
  362. return;
  363. }
  364. }
  365. #define DO_ERROR(trapnr, signr, str, name) 
  366. asmlinkage void do_##name(struct pt_regs * regs, long error_code) 
  367. do_trap(trapnr, signr, str, regs, error_code, NULL); 
  368. }
  369. #define DO_ERROR_INFO(trapnr, signr, str, name, sicode, siaddr) 
  370. asmlinkage void do_##name(struct pt_regs * regs, long error_code) 
  371. siginfo_t info; 
  372. info.si_signo = signr; 
  373. info.si_errno = 0; 
  374. info.si_code = sicode; 
  375. info.si_addr = (void *)siaddr; 
  376. do_trap(trapnr, signr, str, regs, error_code, &info); 
  377. }
  378. DO_ERROR_INFO( 0, SIGFPE,  "divide error", divide_error, FPE_INTDIV, regs->rip)
  379. DO_ERROR( 4, SIGSEGV, "overflow", overflow)
  380. DO_ERROR( 5, SIGSEGV, "bounds", bounds)
  381. DO_ERROR_INFO( 6, SIGILL,  "invalid operand", invalid_op, ILL_ILLOPN, regs->rip)
  382. DO_ERROR( 7, SIGSEGV, "device not available", device_not_available)
  383. DO_ERROR( 8, SIGSEGV, "double fault", double_fault)
  384. DO_ERROR( 9, SIGFPE,  "coprocessor segment overrun", coprocessor_segment_overrun)
  385. DO_ERROR(10, SIGSEGV, "invalid TSS", invalid_TSS)
  386. DO_ERROR(11, SIGBUS,  "segment not present", segment_not_present)
  387. DO_ERROR(12, SIGBUS,  "stack segment", stack_segment)
  388. DO_ERROR_INFO(17, SIGBUS, "alignment check", alignment_check, BUS_ADRALN, get_cr2())
  389. DO_ERROR(18, SIGSEGV, "reserved", reserved)
  390. asmlinkage void do_int3(struct pt_regs * regs, long error_code)
  391. {
  392. if (notify_die(DIE_INT3, "int3", regs, error_code) == NOTIFY_BAD)
  393. return;
  394. do_trap(3, SIGTRAP, "int3", regs, error_code, NULL);
  395. }
  396. extern void dump_pagetable(unsigned long);
  397. asmlinkage void do_general_protection(struct pt_regs * regs, long error_code)
  398. {
  399. #ifdef CONFIG_CHECKING
  400. unsigned long gs; 
  401. struct x8664_pda *pda = cpu_pda + stack_smp_processor_id(); 
  402. rdmsrl(MSR_GS_BASE, gs); 
  403. if (gs != (unsigned long)pda) { 
  404. wrmsrl(MSR_GS_BASE, pda); 
  405. printk("general protection handler: wrong gs %lx expected %pn", gs, pda);
  406. }
  407. }
  408. #endif
  409. if (regs->cs & 3) { 
  410. current->thread.error_code = error_code;
  411. current->thread.trap_no = 13;
  412. if (exception_trace)
  413. printk("%s[%d] general protection rip:%lx rsp:%lx error:%lxn",
  414.        current->comm, current->pid,
  415.        regs->rip,regs->rsp,error_code); 
  416. force_sig(SIGSEGV, current);
  417. return;
  418. /* kernel gp */
  419. {
  420. unsigned long fixup;
  421. fixup = search_exception_table(regs->rip);
  422. if (fixup) {
  423. extern int exception_trace; 
  424. if (exception_trace)
  425. printk(KERN_ERR
  426.        "%s: fixed kernel exception at %lx err:%ldn",
  427.        current->comm, regs->rip, error_code);
  428. regs->rip = fixup;
  429. return;
  430. }
  431. die("general protection fault", regs, error_code);
  432. }
  433. }
  434. static void mem_parity_error(unsigned char reason, struct pt_regs * regs)
  435. {
  436. printk("Uhhuh. NMI received. Dazed and confused, but trying to continuen");
  437. printk("You probably have a hardware problem with your RAM chipsn");
  438. /* Clear and disable the memory parity error line. */
  439. reason = (reason & 0xf) | 4;
  440. outb(reason, 0x61);
  441. }
  442. static void io_check_error(unsigned char reason, struct pt_regs * regs)
  443. {
  444. printk("NMI: IOCK error (debug interrupt?)n");
  445. show_registers(regs);
  446. /* Re-enable the IOCK line, wait for a few seconds */
  447. reason = (reason & 0xf) | 8;
  448. outb(reason, 0x61);
  449. mdelay(2000);
  450. reason &= ~8;
  451. outb(reason, 0x61);
  452. }
  453. static void unknown_nmi_error(unsigned char reason, struct pt_regs * regs)
  454. {
  455. printk("Uhhuh. NMI received for unknown reason %02x.n", reason);
  456. printk("Dazed and confused, but trying to continuen");
  457. printk("Do you have a strange power saving mode enabled?n");
  458. }
  459. asmlinkage void do_nmi(struct pt_regs * regs)
  460. {
  461. unsigned char reason = inb(0x61);
  462. ++nmi_count(smp_processor_id());
  463. if (!(reason & 0xc0)) {
  464. #if CONFIG_X86_LOCAL_APIC
  465. /*
  466.  * Ok, so this is none of the documented NMI sources,
  467.  * so it must be the NMI watchdog.
  468.  */
  469. if (nmi_watchdog) {
  470. nmi_watchdog_tick(regs);
  471. return;
  472. }
  473. #endif
  474. if (notify_die(DIE_NMI, "nmi", regs, reason) == NOTIFY_BAD)
  475. return;
  476. unknown_nmi_error(reason, regs);
  477. return;
  478. }
  479. if (notify_die(DIE_NMI, "nmi", regs, reason) == NOTIFY_BAD)
  480. return; 
  481. if (reason & 0x80)
  482. mem_parity_error(reason, regs);
  483. if (reason & 0x40)
  484. io_check_error(reason, regs);
  485. /*
  486.  * Reassert NMI in case it became active meanwhile
  487.  * as it's edge-triggered.
  488.  */
  489. outb(0x8f, 0x70);
  490. inb(0x71); /* dummy */
  491. outb(0x0f, 0x70);
  492. inb(0x71); /* dummy */
  493. }
  494. asmlinkage void do_debug(struct pt_regs * regs, long error_code)
  495. {
  496. unsigned long condition;
  497. struct task_struct *tsk = current;
  498. siginfo_t info;
  499. #ifdef CONFIG_CHECKING
  500. unsigned long gs; 
  501. struct x8664_pda *pda = cpu_pda + stack_smp_processor_id(); 
  502. rdmsrl(MSR_GS_BASE, gs); 
  503. if (gs != (unsigned long)pda) { 
  504. wrmsrl(MSR_GS_BASE, pda); 
  505. printk("debug handler: wrong gs %lx expected %pn", gs, pda);
  506. }
  507. }
  508. #endif
  509. asm("movq %%db6,%0" : "=r" (condition));
  510. if (notify_die(DIE_DEBUG, "debug", regs, error_code) == NOTIFY_BAD)
  511. return; 
  512. /* If the user set TF, it's simplest to clear it right away. */
  513. /* AK: dubious check, likely wrong */
  514. if ((regs->cs & 3) == 0 && (regs->eflags & TF_MASK))
  515. goto clear_TF;
  516. /* Mask out spurious debug traps due to lazy DR7 setting */
  517. if (condition & (DR_TRAP0|DR_TRAP1|DR_TRAP2|DR_TRAP3)) {
  518. if (!tsk->thread.debugreg[7]) { 
  519. goto clear_dr7;
  520. }
  521. }
  522. tsk->thread.debugreg[6] = condition;
  523. /* Mask out spurious TF errors due to lazy TF clearing */
  524. if (condition & DR_STEP) {
  525. /*
  526.  * The TF error should be masked out only if the current
  527.  * process is not traced and if the TRAP flag has been set
  528.  * previously by a tracing process (condition detected by
  529.  * the PT_DTRACE flag); remember that the i386 TRAP flag
  530.  * can be modified by the process itself in user mode,
  531.  * allowing programs to debug themselves without the ptrace()
  532.  * interface.
  533.  */
  534.                 if ((regs->cs & 3) == 0)
  535.                        goto clear_TF;
  536. if ((tsk->ptrace & (PT_DTRACE|PT_PTRACED)) == PT_DTRACE)
  537. goto clear_TF;
  538. }
  539. /* Ok, finally something we can handle */
  540. tsk->thread.trap_no = 1;
  541. tsk->thread.error_code = error_code;
  542. info.si_signo = SIGTRAP;
  543. info.si_errno = 0;
  544. info.si_code = TRAP_BRKPT;
  545. info.si_addr = ((regs->cs & 3) == 0) ? (void *)tsk->thread.rip : 
  546.                                         (void *)regs->rip;
  547. force_sig_info(SIGTRAP, &info, tsk);
  548. clear_dr7:
  549. asm("movq %0,%%db7"::"r"(0UL));
  550. return;
  551. clear_TF:
  552. regs->eflags &= ~TF_MASK;
  553. return;
  554. }
  555. /*
  556.  * Note that we play around with the 'TS' bit in an attempt to get
  557.  * the correct behaviour even in the presence of the asynchronous
  558.  * IRQ13 behaviour
  559.  */
  560. void math_error(void *rip)
  561. {
  562. struct task_struct * task;
  563. siginfo_t info;
  564. unsigned short cwd, swd;
  565. /*
  566.  * Save the info for the exception handler and clear the error.
  567.  */
  568. task = current;
  569. save_init_fpu(task);
  570. task->thread.trap_no = 16;
  571. task->thread.error_code = 0;
  572. info.si_signo = SIGFPE;
  573. info.si_errno = 0;
  574. info.si_code = __SI_FAULT;
  575. info.si_addr = rip;
  576. /*
  577.  * (~cwd & swd) will mask out exceptions that are not set to unmasked
  578.  * status.  0x3f is the exception bits in these regs, 0x200 is the
  579.  * C1 reg you need in case of a stack fault, 0x040 is the stack
  580.  * fault bit.  We should only be taking one exception at a time,
  581.  * so if this combination doesn't produce any single exception,
  582.  * then we have a bad program that isn't syncronizing its FPU usage
  583.  * and it will suffer the consequences since we won't be able to
  584.  * fully reproduce the context of the exception
  585.  */
  586. cwd = get_fpu_cwd(task);
  587. swd = get_fpu_swd(task);
  588. switch (((~cwd) & swd & 0x3f) | (swd & 0x240)) {
  589. case 0x000:
  590. default:
  591. break;
  592. case 0x001: /* Invalid Op */
  593. case 0x041: /* Stack Fault */
  594. case 0x241: /* Stack Fault | Direction */
  595. info.si_code = FPE_FLTINV;
  596. break;
  597. case 0x002: /* Denormalize */
  598. case 0x010: /* Underflow */
  599. info.si_code = FPE_FLTUND;
  600. break;
  601. case 0x004: /* Zero Divide */
  602. info.si_code = FPE_FLTDIV;
  603. break;
  604. case 0x008: /* Overflow */
  605. info.si_code = FPE_FLTOVF;
  606. break;
  607. case 0x020: /* Precision */
  608. info.si_code = FPE_FLTRES;
  609. break;
  610. }
  611. force_sig_info(SIGFPE, &info, task);
  612. }
  613. asmlinkage void do_coprocessor_error(struct pt_regs * regs, long error_code)
  614. {
  615. math_error((void *)regs->rip);
  616. }
  617. asmlinkage void bad_intr(void)
  618. {
  619. printk("bad interrupt"); 
  620. }
  621. static inline void simd_math_error(void *rip)
  622. {
  623. struct task_struct * task;
  624. siginfo_t info;
  625. unsigned short mxcsr;
  626. /*
  627.  * Save the info for the exception handler and clear the error.
  628.  */
  629. task = current;
  630. save_init_fpu(task);
  631. task->thread.trap_no = 19;
  632. task->thread.error_code = 0;
  633. info.si_signo = SIGFPE;
  634. info.si_errno = 0;
  635. info.si_code = __SI_FAULT;
  636. info.si_addr = rip;
  637. /*
  638.  * The SIMD FPU exceptions are handled a little differently, as there
  639.  * is only a single status/control register.  Thus, to determine which
  640.  * unmasked exception was caught we must mask the exception mask bits
  641.  * at 0x1f80, and then use these to mask the exception bits at 0x3f.
  642.  */
  643. mxcsr = get_fpu_mxcsr(task);
  644. switch (~((mxcsr & 0x1f80) >> 7) & (mxcsr & 0x3f)) {
  645. case 0x000:
  646. default:
  647. break;
  648. case 0x001: /* Invalid Op */
  649. info.si_code = FPE_FLTINV;
  650. break;
  651. case 0x002: /* Denormalize */
  652. case 0x010: /* Underflow */
  653. info.si_code = FPE_FLTUND;
  654. break;
  655. case 0x004: /* Zero Divide */
  656. info.si_code = FPE_FLTDIV;
  657. break;
  658. case 0x008: /* Overflow */
  659. info.si_code = FPE_FLTOVF;
  660. break;
  661. case 0x020: /* Precision */
  662. info.si_code = FPE_FLTRES;
  663. break;
  664. }
  665. force_sig_info(SIGFPE, &info, task);
  666. }
  667. asmlinkage void do_simd_coprocessor_error(struct pt_regs * regs,
  668.   long error_code)
  669. {
  670. simd_math_error((void *)regs->rip);
  671. }
  672. asmlinkage void do_spurious_interrupt_bug(struct pt_regs * regs)
  673. {
  674. }
  675. /*
  676.  *  'math_state_restore()' saves the current math information in the
  677.  * old math state array, and gets the new ones from the current task
  678.  *
  679.  * Careful.. There are problems with IBM-designed IRQ13 behaviour.
  680.  * Don't touch unless you *really* know how it works.
  681.  */
  682. asmlinkage void math_state_restore(void)
  683. {
  684. struct task_struct *me = current;
  685. clts(); /* Allow maths ops (or we recurse) */
  686. if (!me->used_math)
  687. init_fpu();        
  688. restore_fpu_checking(&me->thread.i387.fxsave);
  689. me->flags |= PF_USEDFPU; /* So we fxsave on switch_to() */
  690. }
  691. asmlinkage void math_emulate(void)
  692. {
  693. BUG();
  694. }
  695. void do_call_debug(struct pt_regs *regs) 
  696. notify_die(DIE_CALL, "debug call", regs, 0); 
  697. #ifndef CONFIG_MCE
  698. void do_machine_check(struct pt_regs *regs)
  699. printk("Machine check ignoredn");
  700. #endif
  701. void __init trap_init(void)
  702. {
  703. set_intr_gate(0,&divide_error);
  704. set_intr_gate(1,&debug);
  705. set_intr_gate_ist(2,&nmi,NMI_STACK);
  706. set_system_gate(3,&int3); /* int3-5 can be called from all */
  707. set_system_gate(4,&overflow);
  708. set_system_gate(5,&bounds);
  709. set_intr_gate(6,&invalid_op);
  710. set_intr_gate(7,&device_not_available);
  711. set_intr_gate_ist(8,&double_fault, DOUBLEFAULT_STACK);
  712. set_intr_gate(9,&coprocessor_segment_overrun);
  713. set_intr_gate(10,&invalid_TSS);
  714. set_intr_gate(11,&segment_not_present);
  715. set_intr_gate_ist(12,&stack_segment,STACKFAULT_STACK);
  716. set_intr_gate(13,&general_protection);
  717. set_intr_gate(14,&page_fault);
  718. set_intr_gate(15,&spurious_interrupt_bug);
  719. set_intr_gate(16,&coprocessor_error);
  720. set_intr_gate(17,&alignment_check);
  721. set_intr_gate(18,&machine_check); 
  722. set_intr_gate(19,&simd_coprocessor_error);
  723. #ifdef CONFIG_IA32_EMULATION
  724. set_intr_gate(IA32_SYSCALL_VECTOR, ia32_syscall);
  725. #endif
  726. set_intr_gate(KDB_VECTOR, call_debug);
  727.        
  728. notify_die(DIE_TRAPINIT, "traps initialized", 0, 0); 
  729. /*
  730.  * Should be a barrier for any external CPU state.
  731.  */
  732. cpu_init();
  733. }