home *** CD-ROM | disk | FTP | other *** search
/ Il CD di internet / CD.iso / SOURCE / KERNEL-S / V1.2 / LINUX-1.2 / LINUX-1 / linux / arch / i386 / kernel / traps.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-02-08  |  10.4 KB  |  350 lines

  1. /*
  2.  *  linux/arch/i386/traps.c
  3.  *
  4.  *  Copyright (C) 1991, 1992  Linus Torvalds
  5.  */
  6.  
  7. /*
  8.  * 'Traps.c' handles hardware traps and faults after we have saved some
  9.  * state in 'asm.s'. Currently mostly a debugging-aid, will be extended
  10.  * to mainly kill the offending process (probably by giving it a signal,
  11.  * but possibly by killing it outright if necessary).
  12.  */
  13. #include <linux/head.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/config.h>
  20. #include <linux/timer.h>
  21. #include <linux/mm.h>
  22.  
  23. #include <asm/system.h>
  24. #include <asm/segment.h>
  25. #include <asm/io.h>
  26.  
  27. asmlinkage int system_call(void);
  28. asmlinkage void lcall7(void);
  29. struct desc_struct default_ldt;
  30.  
  31. static inline void console_verbose(void)
  32. {
  33.     extern int console_loglevel;
  34.     console_loglevel = 15;
  35. }
  36.  
  37. #define DO_ERROR(trapnr, signr, str, name, tsk) \
  38. asmlinkage void do_##name(struct pt_regs * regs, long error_code) \
  39. { \
  40.     tsk->tss.error_code = error_code; \
  41.     tsk->tss.trap_no = trapnr; \
  42.     if (signr == SIGTRAP && current->flags & PF_PTRACED) \
  43.         current->blocked &= ~(1 << (SIGTRAP-1)); \
  44.     send_sig(signr, tsk, 1); \
  45.     die_if_kernel(str,regs,error_code); \
  46. }
  47.  
  48. #define get_seg_byte(seg,addr) ({ \
  49. register unsigned char __res; \
  50. __asm__("push %%fs;mov %%ax,%%fs;movb %%fs:%2,%%al;pop %%fs" \
  51.     :"=a" (__res):"0" (seg),"m" (*(addr))); \
  52. __res;})
  53.  
  54. #define get_seg_long(seg,addr) ({ \
  55. register unsigned long __res; \
  56. __asm__("push %%fs;mov %%ax,%%fs;movl %%fs:%2,%%eax;pop %%fs" \
  57.     :"=a" (__res):"0" (seg),"m" (*(addr))); \
  58. __res;})
  59.  
  60. #define _fs() ({ \
  61. register unsigned short __res; \
  62. __asm__("mov %%fs,%%ax":"=a" (__res):); \
  63. __res;})
  64.  
  65. void page_exception(void);
  66.  
  67. asmlinkage void divide_error(void);
  68. asmlinkage void debug(void);
  69. asmlinkage void nmi(void);
  70. asmlinkage void int3(void);
  71. asmlinkage void overflow(void);
  72. asmlinkage void bounds(void);
  73. asmlinkage void invalid_op(void);
  74. asmlinkage void device_not_available(void);
  75. asmlinkage void double_fault(void);
  76. asmlinkage void coprocessor_segment_overrun(void);
  77. asmlinkage void invalid_TSS(void);
  78. asmlinkage void segment_not_present(void);
  79. asmlinkage void stack_segment(void);
  80. asmlinkage void general_protection(void);
  81. asmlinkage void page_fault(void);
  82. asmlinkage void coprocessor_error(void);
  83. asmlinkage void reserved(void);
  84. asmlinkage void alignment_check(void);
  85.  
  86. int kstack_depth_to_print = 24;
  87.  
  88. /*
  89.  * These constants are for searching for possible module text
  90.  * segments.  VMALLOC_OFFSET comes from mm/vmalloc.c; MODULE_RANGE is
  91.  * a guess of how much space is likely to be vmalloced.
  92.  */
  93. #define VMALLOC_OFFSET (8*1024*1024)
  94. #define MODULE_RANGE (8*1024*1024)
  95.  
  96. /*static*/ void die_if_kernel(char * str, struct pt_regs * regs, long err)
  97. {
  98.     int i;
  99.     unsigned long esp;
  100.     unsigned short ss;
  101.     unsigned long *stack, addr, module_start, module_end;
  102.     extern char start_kernel, etext;
  103.  
  104.     esp = (unsigned long) ®s->esp;
  105.     ss = KERNEL_DS;
  106.     if ((regs->eflags & VM_MASK) || (3 & regs->cs) == 3)
  107.         return;
  108.     if (regs->cs & 3) {
  109.         esp = regs->esp;
  110.         ss = regs->ss;
  111.     }
  112.     console_verbose();
  113.     printk("%s: %04lx\n", str, err & 0xffff);
  114.     printk("EIP:    %04x:%08lx\nEFLAGS: %08lx\n", 0xffff & regs->cs,regs->eip,regs->eflags);
  115.     printk("eax: %08lx   ebx: %08lx   ecx: %08lx   edx: %08lx\n",
  116.         regs->eax, regs->ebx, regs->ecx, regs->edx);
  117.     printk("esi: %08lx   edi: %08lx   ebp: %08lx   esp: %08lx\n",
  118.         regs->esi, regs->edi, regs->ebp, esp);
  119.     printk("ds: %04x   es: %04x   fs: %04x   gs: %04x   ss: %04x\n",
  120.         regs->ds, regs->es, regs->fs, regs->gs, ss);
  121.     store_TR(i);
  122.     if (STACK_MAGIC != *(unsigned long *)current->kernel_stack_page)
  123.         printk("Corrupted stack page\n");
  124.     printk("Process %s (pid: %d, process nr: %d, stackpage=%08lx)\nStack: ",
  125.         current->comm, current->pid, 0xffff & i, current->kernel_stack_page);
  126.     stack = (unsigned long *) esp;
  127.     for(i=0; i < kstack_depth_to_print; i++) {
  128.         if (((long) stack & 4095) == 0)
  129.             break;
  130.         if (i && ((i % 8) == 0))
  131.             printk("\n       ");
  132.         printk("%08lx ", get_seg_long(ss,stack++));
  133.     }
  134.     printk("\nCall Trace: ");
  135.     stack = (unsigned long *) esp;
  136.     i = 1;
  137.     module_start = ((high_memory + VMALLOC_OFFSET) & ~(VMALLOC_OFFSET-1));
  138.     module_end = module_start + MODULE_RANGE;
  139.     while (((long) stack & 4095) != 0) {
  140.         addr = get_seg_long(ss, stack++);
  141.         /*
  142.          * If the address is either in the text segment of the
  143.          * kernel, or in the region which contains vmalloc'ed
  144.          * memory, it *may* be the address of a calling
  145.          * routine; if so, print it so that someone tracing
  146.          * down the cause of the crash will be able to figure
  147.          * out the call path that was taken.
  148.          */
  149.         if (((addr >= (unsigned long) &start_kernel) &&
  150.              (addr <= (unsigned long) &etext)) ||
  151.             ((addr >= module_start) && (addr <= module_end))) {
  152.             if (i && ((i % 8) == 0))
  153.                 printk("\n       ");
  154.             printk("%08lx ", addr);
  155.             i++;
  156.         }
  157.     }
  158.     printk("\nCode: ");
  159.     for(i=0;i<20;i++)
  160.         printk("%02x ",0xff & get_seg_byte(regs->cs,(i+(char *)regs->eip)));
  161.     printk("\n");
  162.     do_exit(SIGSEGV);
  163. }
  164.  
  165. DO_ERROR( 0, SIGFPE,  "divide error", divide_error, current)
  166. DO_ERROR( 3, SIGTRAP, "int3", int3, current)
  167. DO_ERROR( 4, SIGSEGV, "overflow", overflow, current)
  168. DO_ERROR( 5, SIGSEGV, "bounds", bounds, current)
  169. DO_ERROR( 6, SIGILL,  "invalid operand", invalid_op, current)
  170. DO_ERROR( 7, SIGSEGV, "device not available", device_not_available, current)
  171. DO_ERROR( 8, SIGSEGV, "double fault", double_fault, current)
  172. DO_ERROR( 9, SIGFPE,  "coprocessor segment overrun", coprocessor_segment_overrun, last_task_used_math)
  173. DO_ERROR(10, SIGSEGV, "invalid TSS", invalid_TSS, current)
  174. DO_ERROR(11, SIGBUS,  "segment not present", segment_not_present, current)
  175. DO_ERROR(12, SIGBUS,  "stack segment", stack_segment, current)
  176. DO_ERROR(15, SIGSEGV, "reserved", reserved, current)
  177. DO_ERROR(17, SIGSEGV, "alignment check", alignment_check, current)
  178.  
  179. asmlinkage void do_general_protection(struct pt_regs * regs, long error_code)
  180. {
  181.     if (regs->eflags & VM_MASK) {
  182.         handle_vm86_fault((struct vm86_regs *) regs, error_code);
  183.         return;
  184.     }
  185.     die_if_kernel("general protection",regs,error_code);
  186.     current->tss.error_code = error_code;
  187.     current->tss.trap_no = 13;
  188.     send_sig(SIGSEGV, current, 1);    
  189. }
  190.  
  191. asmlinkage void do_nmi(struct pt_regs * regs, long error_code)
  192. {
  193. #ifndef CONFIG_IGNORE_NMI
  194.     printk("Uhhuh. NMI received. Dazed and confused, but trying to continue\n");
  195.     printk("You probably have a hardware problem with your RAM chips or a\n");
  196.     printk("power saving mode enabled.\n");
  197. #endif    
  198. }
  199.  
  200. asmlinkage void do_debug(struct pt_regs * regs, long error_code)
  201. {
  202.     if (regs->eflags & VM_MASK) {
  203.         handle_vm86_debug((struct vm86_regs *) regs, error_code);
  204.         return;
  205.     }
  206.     if (current->flags & PF_PTRACED)
  207.         current->blocked &= ~(1 << (SIGTRAP-1));
  208.     send_sig(SIGTRAP, current, 1);
  209.     current->tss.trap_no = 1;
  210.     current->tss.error_code = error_code;
  211.     if ((regs->cs & 3) == 0) {
  212.         /* If this is a kernel mode trap, then reset db7 and allow us to continue */
  213.         __asm__("movl %0,%%db7"
  214.             : /* no output */
  215.             : "r" (0));
  216.         return;
  217.     }
  218.     die_if_kernel("debug",regs,error_code);
  219. }
  220.  
  221. /*
  222.  * Allow the process which triggered the interrupt to recover the error
  223.  * condition.
  224.  *  - the status word is saved in the cs selector.
  225.  *  - the tag word is saved in the operand selector.
  226.  *  - the status word is then cleared and the tags all set to Empty.
  227.  *
  228.  * This will give sufficient information for complete recovery provided that
  229.  * the affected process knows or can deduce the code and data segments
  230.  * which were in force when the exception condition arose.
  231.  *
  232.  * Note that we play around with the 'TS' bit to hopefully get
  233.  * the correct behaviour even in the presence of the asynchronous
  234.  * IRQ13 behaviour
  235.  */
  236. void math_error(void)
  237. {
  238.     struct i387_hard_struct * env;
  239.  
  240.     clts();
  241.     if (!last_task_used_math) {
  242.         __asm__("fnclex");
  243.         return;
  244.     }
  245.     env = &last_task_used_math->tss.i387.hard;
  246.     send_sig(SIGFPE, last_task_used_math, 1);
  247.     last_task_used_math->tss.trap_no = 16;
  248.     last_task_used_math->tss.error_code = 0;
  249.     __asm__ __volatile__("fnsave %0":"=m" (*env));
  250.     last_task_used_math = NULL;
  251.     stts();
  252.     env->fcs = (env->swd & 0x0000ffff) | (env->fcs & 0xffff0000);
  253.     env->fos = env->twd;
  254.     env->swd &= 0xffff3800;
  255.     env->twd = 0xffffffff;
  256. }
  257.  
  258. asmlinkage void do_coprocessor_error(struct pt_regs * regs, long error_code)
  259. {
  260.     ignore_irq13 = 1;
  261.     math_error();
  262. }
  263.  
  264. /*
  265.  *  'math_state_restore()' saves the current math information in the
  266.  * old math state array, and gets the new ones from the current task
  267.  *
  268.  * Careful.. There are problems with IBM-designed IRQ13 behaviour.
  269.  * Don't touch unless you *really* know how it works.
  270.  */
  271. asmlinkage void math_state_restore(void)
  272. {
  273.     __asm__ __volatile__("clts");
  274.     if (last_task_used_math == current)
  275.         return;
  276.     timer_table[COPRO_TIMER].expires = jiffies+50;
  277.     timer_active |= 1<<COPRO_TIMER;    
  278.     if (last_task_used_math)
  279.         __asm__("fnsave %0":"=m" (last_task_used_math->tss.i387));
  280.     else
  281.         __asm__("fnclex");
  282.     last_task_used_math = current;
  283.     if (current->used_math) {
  284.         __asm__("frstor %0": :"m" (current->tss.i387));
  285.     } else {
  286.         __asm__("fninit");
  287.         current->used_math=1;
  288.     }
  289.     timer_active &= ~(1<<COPRO_TIMER);
  290. }
  291.  
  292. #ifndef CONFIG_MATH_EMULATION
  293.  
  294. asmlinkage void math_emulate(long arg)
  295. {
  296.   printk("math-emulation not enabled and no coprocessor found.\n");
  297.   printk("killing %s.\n",current->comm);
  298.   send_sig(SIGFPE,current,1);
  299.   schedule();
  300. }
  301.  
  302. #endif /* CONFIG_MATH_EMULATION */
  303.  
  304. void trap_init(void)
  305. {
  306.     int i;
  307.     struct desc_struct * p;
  308.  
  309.     if (strncmp((char*)0x0FFFD9, "EISA", 4) == 0)
  310.         EISA_bus = 1;
  311.     set_call_gate(&default_ldt,lcall7);
  312.     set_trap_gate(0,÷_error);
  313.     set_trap_gate(1,&debug);
  314.     set_trap_gate(2,&nmi);
  315.     set_system_gate(3,&int3);    /* int3-5 can be called from all */
  316.     set_system_gate(4,&overflow);
  317.     set_system_gate(5,&bounds);
  318.     set_trap_gate(6,&invalid_op);
  319.     set_trap_gate(7,&device_not_available);
  320.     set_trap_gate(8,&double_fault);
  321.     set_trap_gate(9,&coprocessor_segment_overrun);
  322.     set_trap_gate(10,&invalid_TSS);
  323.     set_trap_gate(11,&segment_not_present);
  324.     set_trap_gate(12,&stack_segment);
  325.     set_trap_gate(13,&general_protection);
  326.     set_trap_gate(14,&page_fault);
  327.     set_trap_gate(15,&reserved);
  328.     set_trap_gate(16,&coprocessor_error);
  329.     set_trap_gate(17,&alignment_check);
  330.     for (i=18;i<48;i++)
  331.         set_trap_gate(i,&reserved);
  332.     set_system_gate(0x80,&system_call);
  333. /* set up GDT task & ldt entries */
  334.     p = gdt+FIRST_TSS_ENTRY;
  335.     set_tss_desc(p, &init_task.tss);
  336.     p++;
  337.     set_ldt_desc(p, &default_ldt, 1);
  338.     p++;
  339.     for(i=1 ; i<NR_TASKS ; i++) {
  340.         p->a=p->b=0;
  341.         p++;
  342.         p->a=p->b=0;
  343.         p++;
  344.     }
  345. /* Clear NT, so that we won't have troubles with that later on */
  346.     __asm__("pushfl ; andl $0xffffbfff,(%esp) ; popfl");
  347.     load_TR(0);
  348.     load_ldt(0);
  349. }
  350.