vserver 1.9.3
[linux-2.6.git] / arch / x86_64 / kernel / traps.c
index d82da80..c0a31a4 100644 (file)
@@ -110,12 +110,13 @@ unsigned long *in_exception_stack(int cpu, unsigned long stack)
 { 
        int k;
        for (k = 0; k < N_EXCEPTION_STACKS; k++) {
-               unsigned long end = init_tss[cpu].ist[k] + EXCEPTION_STKSZ; 
+               struct tss_struct *tss = &per_cpu(init_tss, cpu);
+               unsigned long end = tss->ist[k] + EXCEPTION_STKSZ;
 
-               if (stack >= init_tss[cpu].ist[k]  && stack <= end) 
+               if (stack >= tss->ist[k]  && stack <= end)
                        return (unsigned long *)end;
        }
-       return 0;
+       return NULL;
 } 
 
 /*
@@ -140,7 +141,7 @@ void show_trace(unsigned long *stack)
        if (estack_end) { 
                while (stack < estack_end) { 
                        addr = *stack++; 
-                       if (kernel_text_address(addr)) {  
+                       if (__kernel_text_address(addr)) {
                                i += printk_address(addr);
                                i += printk(" "); 
                                if (i > 50) {
@@ -169,7 +170,7 @@ void show_trace(unsigned long *stack)
                         * down the cause of the crash will be able to figure
                         * out the call path that was taken.
                         */
-                        if (kernel_text_address(addr)) {  
+                        if (__kernel_text_address(addr)) {
                                 i += printk_address(addr);
                                 i += printk(" "); 
                                 if (i > 50) { 
@@ -185,7 +186,7 @@ void show_trace(unsigned long *stack)
 
        while (((long) stack & (THREAD_SIZE-1)) != 0) {
                addr = *stack++;
-               if (kernel_text_address(addr)) {         
+               if (__kernel_text_address(addr)) {
                        i += printk_address(addr);
                        i += printk(" "); 
                        if (i > 50) { 
@@ -352,7 +353,7 @@ void __die(const char * str, struct pt_regs * regs, long err)
 #ifdef CONFIG_DEBUG_PAGEALLOC
        printk("DEBUG_PAGEALLOC");
 #endif
-               printk("\n");
+       printk("\n");
        notify_die(DIE_OOPS, (char *)str, regs, err, 255, SIGSEGV);
        show_registers(regs);
        /* Executive summary in case the oops scrolled away */
@@ -436,7 +437,8 @@ static void do_trap(int trapnr, int signr, char *str,
 #define DO_ERROR(trapnr, signr, str, name) \
 asmlinkage void do_##name(struct pt_regs * regs, long error_code) \
 { \
-       if (notify_die(DIE_TRAP, str, regs, error_code, trapnr, signr) == NOTIFY_BAD) \
+       if (notify_die(DIE_TRAP, str, regs, error_code, trapnr, signr) \
+                                                       == NOTIFY_STOP) \
                return; \
        do_trap(trapnr, signr, str, regs, error_code, NULL); \
 }
@@ -448,8 +450,9 @@ asmlinkage void do_##name(struct pt_regs * regs, long error_code) \
        info.si_signo = signr; \
        info.si_errno = 0; \
        info.si_code = sicode; \
-       info.si_addr = (void *)siaddr; \
-       if (notify_die(DIE_TRAP, str, regs, error_code, trapnr, signr) == NOTIFY_BAD) \
+       info.si_addr = (void __user *)siaddr; \
+       if (notify_die(DIE_TRAP, str, regs, error_code, trapnr, signr) \
+                                                       == NOTIFY_STOP) \
                return; \
        do_trap(trapnr, signr, str, regs, error_code, &info); \
 }
@@ -463,14 +466,15 @@ DO_ERROR( 7, SIGSEGV, "device not available", device_not_available)
 DO_ERROR( 9, SIGFPE,  "coprocessor segment overrun", coprocessor_segment_overrun)
 DO_ERROR(10, SIGSEGV, "invalid TSS", invalid_TSS)
 DO_ERROR(11, SIGBUS,  "segment not present", segment_not_present)
-DO_ERROR_INFO(17, SIGBUS, "alignment check", alignment_check, BUS_ADRALN, get_cr2())
+DO_ERROR_INFO(17, SIGBUS, "alignment check", alignment_check, BUS_ADRALN, 0)
 DO_ERROR(18, SIGSEGV, "reserved", reserved)
 
 #define DO_ERROR_STACK(trapnr, signr, str, name) \
 asmlinkage void *do_##name(struct pt_regs * regs, long error_code) \
 { \
        struct pt_regs *pr = ((struct pt_regs *)(current->thread.rsp0))-1; \
-       if (notify_die(DIE_TRAP, str, regs, error_code, trapnr, signr) == NOTIFY_BAD) \
+       if (notify_die(DIE_TRAP, str, regs, error_code, trapnr, signr) \
+                                                       == NOTIFY_STOP) \
                return regs; \
        if (regs->cs & 3) { \
                memcpy(pr, regs, sizeof(struct pt_regs)); \
@@ -513,7 +517,7 @@ asmlinkage void do_general_protection(struct pt_regs * regs, long error_code)
                tsk->thread.error_code = error_code;
                tsk->thread.trap_no = 13;
                force_sig(SIGSEGV, tsk);
-       return;
+               return;
        } 
 
        /* kernel gp */
@@ -564,7 +568,8 @@ asmlinkage void default_do_nmi(struct pt_regs * regs)
        unsigned char reason = inb(0x61);
 
        if (!(reason & 0xc0)) {
-               if (notify_die(DIE_NMI_IPI, "nmi_ipi", regs, reason, 0, SIGINT) == NOTIFY_BAD)
+               if (notify_die(DIE_NMI_IPI, "nmi_ipi", regs, reason, 0, SIGINT)
+                                                               == NOTIFY_STOP)
                        return;
 #ifdef CONFIG_X86_LOCAL_APIC
                /*
@@ -579,7 +584,7 @@ asmlinkage void default_do_nmi(struct pt_regs * regs)
                unknown_nmi_error(reason, regs);
                return;
        }
-       if (notify_die(DIE_NMI, "nmi", regs, reason, 0, SIGINT) == NOTIFY_BAD)
+       if (notify_die(DIE_NMI, "nmi", regs, reason, 0, SIGINT) == NOTIFY_STOP)
                return; 
        if (reason & 0x80)
                mem_parity_error(reason, regs);
@@ -662,7 +667,7 @@ asmlinkage void *do_debug(struct pt_regs * regs, unsigned long error_code)
        if ((regs->cs & 3) == 0) 
                goto clear_dr7; 
 
-       info.si_addr = (void *)regs->rip;
+       info.si_addr = (void __user *)regs->rip;
        force_sig_info(SIGTRAP, &info, tsk);    
 clear_dr7:
        asm volatile("movq %0,%%db7"::"r"(0UL));
@@ -670,27 +675,53 @@ clear_dr7:
        return regs;
 
 clear_TF_reenable:
-       printk("clear_tf_reenable\n");
        set_tsk_thread_flag(tsk, TIF_SINGLESTEP);
 
 clear_TF:
        /* RED-PEN could cause spurious errors */
        if (notify_die(DIE_DEBUG, "debug2", regs, condition, 1, SIGTRAP) 
-           != NOTIFY_BAD)
+                                                               != NOTIFY_STOP)
        regs->eflags &= ~TF_MASK;
        return regs;    
 }
 
+static int kernel_math_error(struct pt_regs *regs, char *str)
+{
+       const struct exception_table_entry *fixup;
+       fixup = search_exception_tables(regs->rip);
+       if (fixup) {
+               regs->rip = fixup->fixup;
+               return 1;
+       }
+       notify_die(DIE_GPF, str, regs, 0, 16, SIGFPE);
+#if 0
+       /* This should be a die, but warn only for now */
+       die(str, regs, 0);
+#else
+       printk(KERN_DEBUG "%s: %s at ", current->comm, str);
+       printk_address(regs->rip);
+       printk("\n");
+#endif
+       return 0;
+}
+
 /*
  * Note that we play around with the 'TS' bit in an attempt to get
  * the correct behaviour even in the presence of the asynchronous
  * IRQ13 behaviour
  */
-void math_error(void *rip)
+asmlinkage void do_coprocessor_error(struct pt_regs *regs)
 {
+       void __user *rip = (void __user *)(regs->rip);
        struct task_struct * task;
        siginfo_t info;
        unsigned short cwd, swd;
+
+       conditional_sti(regs);
+       if ((regs->cs & 3) == 0 &&
+           kernel_math_error(regs, "kernel x87 math error"))
+               return;
+
        /*
         * Save the info for the exception handler and clear the error.
         */
@@ -740,23 +771,23 @@ void math_error(void *rip)
        force_sig_info(SIGFPE, &info, task);
 }
 
-asmlinkage void do_coprocessor_error(struct pt_regs * regs)
-{
-       conditional_sti(regs);
-       math_error((void *)regs->rip);
-}
-
 asmlinkage void bad_intr(void)
 {
        printk("bad interrupt"); 
 }
 
-static inline void simd_math_error(void *rip)
+asmlinkage void do_simd_coprocessor_error(struct pt_regs *regs)
 {
+       void __user *rip = (void __user *)(regs->rip);
        struct task_struct * task;
        siginfo_t info;
        unsigned short mxcsr;
 
+       conditional_sti(regs);
+       if ((regs->cs & 3) == 0 &&
+               kernel_math_error(regs, "simd math error"))
+               return;
+
        /*
         * Save the info for the exception handler and clear the error.
         */
@@ -799,12 +830,6 @@ static inline void simd_math_error(void *rip)
        force_sig_info(SIGFPE, &info, task);
 }
 
-asmlinkage void do_simd_coprocessor_error(struct pt_regs * regs)
-{
-       conditional_sti(regs);
-               simd_math_error((void *)regs->rip);
-}
-
 asmlinkage void do_spurious_interrupt_bug(struct pt_regs * regs)
 {
 }