root/kernel/traps.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. die_if_kernel
  2. do_double_fault
  3. do_general_protection
  4. do_alignment_check
  5. do_divide_error
  6. do_int3
  7. do_nmi
  8. do_debug
  9. do_overflow
  10. do_bounds
  11. do_invalid_op
  12. do_device_not_available
  13. do_coprocessor_segment_overrun
  14. do_invalid_TSS
  15. do_segment_not_present
  16. do_stack_segment
  17. math_error
  18. do_coprocessor_error
  19. do_reserved
  20. trap_init

   1 /*
   2  *  linux/kernel/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/segment.h>
  19 #include <linux/ptrace.h>
  20 
  21 #include <asm/system.h>
  22 #include <asm/segment.h>
  23 #include <asm/io.h>
  24 
  25 #define get_seg_byte(seg,addr) ({ \
  26 register char __res; \
  27 __asm__("push %%fs;mov %%ax,%%fs;movb %%fs:%2,%%al;pop %%fs" \
  28         :"=a" (__res):"0" (seg),"m" (*(addr))); \
  29 __res;})
  30 
  31 #define get_seg_long(seg,addr) ({ \
  32 register unsigned long __res; \
  33 __asm__("push %%fs;mov %%ax,%%fs;movl %%fs:%2,%%eax;pop %%fs" \
  34         :"=a" (__res):"0" (seg),"m" (*(addr))); \
  35 __res;})
  36 
  37 #define _fs() ({ \
  38 register unsigned short __res; \
  39 __asm__("mov %%fs,%%ax":"=a" (__res):); \
  40 __res;})
  41 
  42 void page_exception(void);
  43 
  44 extern "C" void divide_error(void);
  45 extern "C" void debug(void);
  46 extern "C" void nmi(void);
  47 extern "C" void int3(void);
  48 extern "C" void overflow(void);
  49 extern "C" void bounds(void);
  50 extern "C" void invalid_op(void);
  51 extern "C" void device_not_available(void);
  52 extern "C" void double_fault(void);
  53 extern "C" void coprocessor_segment_overrun(void);
  54 extern "C" void invalid_TSS(void);
  55 extern "C" void segment_not_present(void);
  56 extern "C" void stack_segment(void);
  57 extern "C" void general_protection(void);
  58 extern "C" void page_fault(void);
  59 extern "C" void coprocessor_error(void);
  60 extern "C" void reserved(void);
  61 extern "C" void alignment_check(void);
  62 
  63 /*static*/ void die_if_kernel(char * str, struct pt_regs * regs, long err)
     /* [previous][next][first][last][top][bottom][index][help] */
  64 {
  65         int i;
  66 
  67         if ((regs->eflags & VM_MASK) || ((0xffff & regs->cs) == USER_CS))
  68                 return;
  69         printk("%s: %04x\n", str, err & 0xffff);
  70         printk("EIP:    %04x:%p\nEFLAGS: %p\n", 0xffff & regs->cs,regs->eip,regs->eflags);
  71         printk("eax: %08x   ebx: %08x   ecx: %08x   edx: %08x\n",
  72                 regs->eax, regs->ebx, regs->ecx, regs->edx);
  73         printk("esi: %08x   edi: %08x   ebp: %08x\n",
  74                 regs->esi, regs->edi, regs->ebp);
  75         printk("ds: %04x   es: %04x   fs: %04x   gs: %04x\n",
  76                 regs->ds, regs->es, regs->fs, regs->gs);
  77         store_TR(i);
  78         printk("Pid: %d, process nr: %d\n", current->pid, 0xffff & i);
  79         for(i=0;i<10;i++)
  80                 printk("%02x ",0xff & get_seg_byte(regs->cs,(i+(char *)regs->eip)));
  81         printk("\n");
  82         do_exit(SIGSEGV);
  83 }
  84 
  85 extern "C" void do_double_fault(struct pt_regs * regs, long error_code)
     /* [previous][next][first][last][top][bottom][index][help] */
  86 {
  87         send_sig(SIGSEGV, current, 1);
  88         die_if_kernel("double fault",regs,error_code);
  89 }
  90 
  91 extern "C" void do_general_protection(struct pt_regs * regs, long error_code)
     /* [previous][next][first][last][top][bottom][index][help] */
  92 {
  93         send_sig(SIGSEGV, current, 1);
  94         die_if_kernel("general protection",regs,error_code);
  95 }
  96 
  97 extern "C" void do_alignment_check(struct pt_regs * regs, long error_code)
     /* [previous][next][first][last][top][bottom][index][help] */
  98 {
  99         send_sig(SIGSEGV, current, 1);
 100         die_if_kernel("alignment check",regs,error_code);
 101 }
 102 
 103 extern "C" void do_divide_error(struct pt_regs * regs, long error_code)
     /* [previous][next][first][last][top][bottom][index][help] */
 104 {
 105         send_sig(SIGFPE, current, 1);
 106         die_if_kernel("divide error",regs,error_code);
 107 }
 108 
 109 extern "C" void do_int3(struct pt_regs * regs, long error_code)
     /* [previous][next][first][last][top][bottom][index][help] */
 110 {
 111         if (current->flags & PF_PTRACED)
 112                 current->blocked &= ~(1 << (SIGTRAP-1));
 113         send_sig(SIGTRAP, current, 1);
 114         die_if_kernel("int3",regs,error_code);
 115 }
 116 
 117 extern "C" void do_nmi(struct pt_regs * regs, long error_code)
     /* [previous][next][first][last][top][bottom][index][help] */
 118 {
 119         printk("Uhhuh. NMI received. Dazed and confused, but trying to continue\n");
 120 }
 121 
 122 extern "C" void do_debug(struct pt_regs * regs, long error_code)
     /* [previous][next][first][last][top][bottom][index][help] */
 123 {
 124         if (current->flags & PF_PTRACED)
 125                 current->blocked &= ~(1 << (SIGTRAP-1));
 126         send_sig(SIGTRAP, current, 1);
 127         die_if_kernel("debug",regs,error_code);
 128 }
 129 
 130 extern "C" void do_overflow(struct pt_regs * regs, long error_code)
     /* [previous][next][first][last][top][bottom][index][help] */
 131 {
 132         send_sig(SIGSEGV, current, 1);
 133         die_if_kernel("overflow",regs,error_code);
 134 }
 135 
 136 extern "C" void do_bounds(struct pt_regs * regs, long error_code)
     /* [previous][next][first][last][top][bottom][index][help] */
 137 {
 138         send_sig(SIGSEGV, current, 1);
 139         die_if_kernel("bounds",regs,error_code);
 140 }
 141 
 142 extern "C" void do_invalid_op(struct pt_regs * regs, long error_code)
     /* [previous][next][first][last][top][bottom][index][help] */
 143 {
 144         send_sig(SIGILL, current, 1);
 145         die_if_kernel("invalid operand",regs,error_code);
 146 }
 147 
 148 extern "C" void do_device_not_available(struct pt_regs * regs, long error_code)
     /* [previous][next][first][last][top][bottom][index][help] */
 149 {
 150         send_sig(SIGSEGV, current, 1);
 151         die_if_kernel("device not available",regs,error_code);
 152 }
 153 
 154 extern "C" void do_coprocessor_segment_overrun(struct pt_regs * regs, long error_code)
     /* [previous][next][first][last][top][bottom][index][help] */
 155 {
 156         send_sig(SIGFPE, last_task_used_math, 1);
 157         die_if_kernel("coprocessor segment overrun",regs,error_code);
 158 }
 159 
 160 extern "C" void do_invalid_TSS(struct pt_regs * regs,long error_code)
     /* [previous][next][first][last][top][bottom][index][help] */
 161 {
 162         send_sig(SIGSEGV, current, 1);
 163         die_if_kernel("invalid TSS",regs,error_code);
 164 }
 165 
 166 extern "C" void do_segment_not_present(struct pt_regs * regs,long error_code)
     /* [previous][next][first][last][top][bottom][index][help] */
 167 {
 168         send_sig(SIGSEGV, current, 1);
 169         die_if_kernel("segment not present",regs,error_code);
 170 }
 171 
 172 extern "C" void do_stack_segment(struct pt_regs * regs,long error_code)
     /* [previous][next][first][last][top][bottom][index][help] */
 173 {
 174         send_sig(SIGSEGV, current, 1);
 175         die_if_kernel("stack segment",regs,error_code);
 176 }
 177 
 178 /*
 179  * Allow the process which triggered the interrupt to recover the error
 180  * condition.
 181  *  - the status word is saved in the cs selector.
 182  *  - the tag word is saved in the operand selector.
 183  *  - the status word is then cleared and the tags all set to Empty.
 184  *
 185  * This will give sufficient information for complete recovery provided that
 186  * the affected process knows or can deduce the code and data segments
 187  * which were in force when the exception condition arose.
 188  *
 189  * Note that we play around with the 'TS' bit to hopefully get
 190  * the correct behaviour even in the presense of the asynchronous
 191  * IRQ13 behaviour
 192  */
 193 void math_error(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 194 {
 195         struct i387_hard_struct * env;
 196 
 197         clts();
 198         if (!last_task_used_math) {
 199                 __asm__("fnclex");
 200                 return;
 201         }
 202         env = &last_task_used_math->tss.i387.hard;
 203         send_sig(SIGFPE, last_task_used_math, 1);
 204         __asm__ __volatile__("fnsave %0":"=m" (*env));
 205         last_task_used_math = NULL;
 206         stts();
 207         env->fcs = (env->swd & 0x0000ffff) | (env->fcs & 0xffff0000);
 208         env->fos = env->twd;
 209         env->swd &= 0xffff0000;
 210         env->twd = 0xffffffff;
 211 }
 212 
 213 extern "C" void do_coprocessor_error(struct pt_regs * regs, long error_code)
     /* [previous][next][first][last][top][bottom][index][help] */
 214 {
 215         ignore_irq13 = 1;
 216         math_error();
 217 }
 218 
 219 extern "C" void do_reserved(struct pt_regs * regs, long error_code)
     /* [previous][next][first][last][top][bottom][index][help] */
 220 {
 221         send_sig(SIGSEGV, current, 1);
 222         die_if_kernel("reserved (15,17-47) error",regs,error_code);
 223 }
 224 
 225 void trap_init(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 226 {
 227         int i;
 228 
 229         set_trap_gate(0,&divide_error);
 230         set_trap_gate(1,&debug);
 231         set_trap_gate(2,&nmi);
 232         set_system_gate(3,&int3);       /* int3-5 can be called from all */
 233         set_system_gate(4,&overflow);
 234         set_system_gate(5,&bounds);
 235         set_trap_gate(6,&invalid_op);
 236         set_trap_gate(7,&device_not_available);
 237         set_trap_gate(8,&double_fault);
 238         set_trap_gate(9,&coprocessor_segment_overrun);
 239         set_trap_gate(10,&invalid_TSS);
 240         set_trap_gate(11,&segment_not_present);
 241         set_trap_gate(12,&stack_segment);
 242         set_trap_gate(13,&general_protection);
 243         set_trap_gate(14,&page_fault);
 244         set_trap_gate(15,&reserved);
 245         set_trap_gate(16,&coprocessor_error);
 246         set_trap_gate(17,&alignment_check);
 247         for (i=18;i<48;i++)
 248                 set_trap_gate(i,&reserved);
 249 }

/* [previous][next][first][last][top][bottom][index][help] */