]> pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - arch/x86/kernel/traps_32.c
x86: traps_xx: various small changes
[linux-2.6-omap-h63xx.git] / arch / x86 / kernel / traps_32.c
index 471e694d6713193baa5a25dac995f177ef34abf2..8a768973c4f01bdf4b9317d0b23800a233608db9 100644 (file)
@@ -1,5 +1,6 @@
 /*
  *  Copyright (C) 1991, 1992  Linus Torvalds
+ *  Copyright (C) 2000, 2001, 2002 Andi Kleen, SuSE Labs
  *
  *  Pentium III FXSR, SSE support
  *     Gareth Hughes <gareth@valinux.com>, May 2000
@@ -60,8 +61,6 @@
 
 #include "mach_traps.h"
 
-int panic_on_unrecovered_nmi;
-
 DECLARE_BITMAP(used_vectors, NR_VECTORS);
 EXPORT_SYMBOL_GPL(used_vectors);
 
@@ -98,19 +97,22 @@ asmlinkage void alignment_check(void);
 asmlinkage void spurious_interrupt_bug(void);
 asmlinkage void machine_check(void);
 
+int panic_on_unrecovered_nmi;
 int kstack_depth_to_print = 24;
 static unsigned int code_bytes = 64;
+static int ignore_nmis;
+static int die_counter;
 
 void printk_address(unsigned long address, int reliable)
 {
 #ifdef CONFIG_KALLSYMS
-       char namebuf[KSYM_NAME_LEN];
        unsigned long offset = 0;
        unsigned long symsize;
        const char *symname;
-       char reliab[4] = "";
-       char *delim = ":";
        char *modname;
+       char *delim = ":";
+       char namebuf[KSYM_NAME_LEN];
+       char reliab[4] = "";
 
        symname = kallsyms_lookup(address, &symsize, &offset,
                                        &modname, namebuf);
@@ -130,22 +132,23 @@ void printk_address(unsigned long address, int reliable)
 #endif
 }
 
-static inline int valid_stack_ptr(struct thread_info *tinfo, void *p, unsigned size)
+static inline int valid_stack_ptr(struct thread_info *tinfo,
+                       void *p, unsigned int size)
 {
-       return  p > (void *)tinfo &&
-               p <= (void *)tinfo + THREAD_SIZE - size;
+       void *t = tinfo;
+       return  p > t && p <= t + THREAD_SIZE - size;
 }
 
 /* The form of the top of the frame on the stack */
 struct stack_frame {
-       struct stack_frame      *next_frame;
-       unsigned long           return_address;
+       struct stack_frame *next_frame;
+       unsigned long return_address;
 };
 
 static inline unsigned long
 print_context_stack(struct thread_info *tinfo,
-                   unsigned long *stack, unsigned long bp,
-                   const struct stacktrace_ops *ops, void *data)
+               unsigned long *stack, unsigned long bp,
+               const struct stacktrace_ops *ops, void *data)
 {
        struct stack_frame *frame = (struct stack_frame *)bp;
 
@@ -167,8 +170,6 @@ print_context_stack(struct thread_info *tinfo,
        return bp;
 }
 
-#define MSG(msg)               ops->warning(data, msg)
-
 void dump_trace(struct task_struct *task, struct pt_regs *regs,
                unsigned long *stack, unsigned long bp,
                const struct stacktrace_ops *ops, void *data)
@@ -178,7 +179,6 @@ void dump_trace(struct task_struct *task, struct pt_regs *regs,
 
        if (!stack) {
                unsigned long dummy;
-
                stack = &dummy;
                if (task != current)
                        stack = (unsigned long *)task->thread.sp;
@@ -196,7 +196,7 @@ void dump_trace(struct task_struct *task, struct pt_regs *regs,
        }
 #endif
 
-       while (1) {
+       for (;;) {
                struct thread_info *context;
 
                context = (struct thread_info *)
@@ -248,10 +248,10 @@ static void print_trace_address(void *data, unsigned long addr, int reliable)
 }
 
 static const struct stacktrace_ops print_trace_ops = {
-       .warning                = print_trace_warning,
-       .warning_symbol         = print_trace_warning_symbol,
-       .stack                  = print_trace_stack,
-       .address                = print_trace_address,
+       .warning = print_trace_warning,
+       .warning_symbol = print_trace_warning_symbol,
+       .stack = print_trace_stack,
+       .address = print_trace_address,
 };
 
 static void
@@ -351,15 +351,14 @@ void show_registers(struct pt_regs *regs)
                printk(KERN_EMERG "Code: ");
 
                ip = (u8 *)regs->ip - code_prologue;
-               if (ip < (u8 *)PAGE_OFFSET ||
-                       probe_kernel_address(ip, c)) {
+               if (ip < (u8 *)PAGE_OFFSET || probe_kernel_address(ip, c)) {
                        /* try starting at EIP */
                        ip = (u8 *)regs->ip;
                        code_len = code_len - code_prologue + 1;
                }
                for (i = 0; i < code_len; i++, ip++) {
                        if (ip < (u8 *)PAGE_OFFSET ||
-                               probe_kernel_address(ip, c)) {
+                                       probe_kernel_address(ip, c)) {
                                printk(" Bad EIP value.");
                                break;
                        }
@@ -384,8 +383,6 @@ int is_valid_bugaddr(unsigned long ip)
        return ud2 == 0x0b0f;
 }
 
-static int die_counter;
-
 int __kprobes __die(const char *str, struct pt_regs *regs, long err)
 {
        unsigned short ss;
@@ -402,26 +399,22 @@ int __kprobes __die(const char *str, struct pt_regs *regs, long err)
        printk("DEBUG_PAGEALLOC");
 #endif
        printk("\n");
-
        if (notify_die(DIE_OOPS, str, regs, err,
-                       current->thread.trap_no, SIGSEGV) != NOTIFY_STOP) {
-
-               show_registers(regs);
-               /* Executive summary in case the oops scrolled away */
-               sp = (unsigned long) (&regs->sp);
-               savesegment(ss, ss);
-               if (user_mode(regs)) {
-                       sp = regs->sp;
-                       ss = regs->ss & 0xffff;
-               }
-               printk(KERN_EMERG "EIP: [<%08lx>] ", regs->ip);
-               print_symbol("%s", regs->ip);
-               printk(" SS:ESP %04x:%08lx\n", ss, sp);
+                       current->thread.trap_no, SIGSEGV) == NOTIFY_STOP)
+               return 1;
 
-               return 0;
+       show_registers(regs);
+       /* Executive summary in case the oops scrolled away */
+       sp = (unsigned long) (&regs->sp);
+       savesegment(ss, ss);
+       if (user_mode(regs)) {
+               sp = regs->sp;
+               ss = regs->ss & 0xffff;
        }
-
-       return 1;
+       printk(KERN_EMERG "EIP: [<%08lx>] ", regs->ip);
+       print_symbol("%s", regs->ip);
+       printk(" SS:ESP %04x:%08lx\n", ss, sp);
+       return 0;
 }
 
 /*
@@ -544,8 +537,9 @@ vm86_trap:
 #define DO_ERROR(trapnr, signr, str, name)                             \
 void do_##name(struct pt_regs *regs, long error_code)                  \
 {                                                                      \
+       trace_hardirqs_fixup();                                         \
        if (notify_die(DIE_TRAP, str, regs, error_code, trapnr, signr)  \
-                                               == NOTIFY_STOP)         \
+                                                       == NOTIFY_STOP) \
                return;                                                 \
        do_trap(trapnr, signr, str, 0, regs, error_code, NULL);         \
 }
@@ -561,7 +555,7 @@ void do_##name(struct pt_regs *regs, long error_code)                       \
        info.si_code = sicode;                                          \
        info.si_addr = (void __user *)siaddr;                           \
        if (notify_die(DIE_TRAP, str, regs, error_code, trapnr, signr)  \
-                                               == NOTIFY_STOP)         \
+                                                       == NOTIFY_STOP) \
                return;                                                 \
        do_trap(trapnr, signr, str, 0, regs, error_code, &info);        \
 }
@@ -570,7 +564,7 @@ void do_##name(struct pt_regs *regs, long error_code)                       \
 void do_##name(struct pt_regs *regs, long error_code)                  \
 {                                                                      \
        if (notify_die(DIE_TRAP, str, regs, error_code, trapnr, signr)  \
-                                               == NOTIFY_STOP)         \
+                                                       == NOTIFY_STOP) \
                return;                                                 \
        do_trap(trapnr, signr, str, 1, regs, error_code, NULL);         \
 }
@@ -585,27 +579,29 @@ void do_##name(struct pt_regs *regs, long error_code)                     \
        info.si_addr = (void __user *)siaddr;                           \
        trace_hardirqs_fixup();                                         \
        if (notify_die(DIE_TRAP, str, regs, error_code, trapnr, signr)  \
-                                               == NOTIFY_STOP)         \
+                                                       == NOTIFY_STOP) \
                return;                                                 \
        do_trap(trapnr, signr, str, 1, regs, error_code, &info);        \
 }
 
-DO_VM86_ERROR_INFO(0, SIGFPE,  "divide error", divide_error, FPE_INTDIV, regs->ip)
+DO_VM86_ERROR_INFO(0, SIGFPE, "divide error", divide_error, FPE_INTDIV, regs->ip)
 #ifndef CONFIG_KPROBES
 DO_VM86_ERROR(3, SIGTRAP, "int3", int3)
 #endif
 DO_VM86_ERROR(4, SIGSEGV, "overflow", overflow)
 DO_VM86_ERROR(5, SIGSEGV, "bounds", bounds)
-DO_ERROR_INFO(6, SIGILL,  "invalid opcode", invalid_op, ILL_ILLOPN, regs->ip, 0)
-DO_ERROR(9, SIGFPE,  "coprocessor segment overrun", coprocessor_segment_overrun)
+DO_ERROR_INFO(6, SIGILL, "invalid opcode", invalid_op, ILL_ILLOPN, regs->ip, 0)
+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(12, SIGBUS,  "stack segment", stack_segment)
+DO_ERROR(11, SIGBUS, "segment not present", segment_not_present)
+DO_ERROR(12, SIGBUS, "stack segment", stack_segment)
 DO_ERROR_INFO(17, SIGBUS, "alignment check", alignment_check, BUS_ADRALN, 0, 0)
-DO_ERROR_INFO(32, SIGSEGV, "iret exception", iret_error, ILL_BADSTK, 0, 1)
+DO_ERROR_INFO(32, SIGILL, "iret exception", iret_error, ILL_BADSTK, 0, 1)
 
-void __kprobes do_general_protection(struct pt_regs *regs, long error_code)
+void __kprobes
+do_general_protection(struct pt_regs *regs, long error_code)
 {
+       struct task_struct *tsk;
        struct thread_struct *thread;
        struct tss_struct *tss;
        int cpu;
@@ -646,23 +642,24 @@ void __kprobes do_general_protection(struct pt_regs *regs, long error_code)
        if (regs->flags & X86_VM_MASK)
                goto gp_in_vm86;
 
+       tsk = current;
        if (!user_mode(regs))
                goto gp_in_kernel;
 
-       current->thread.error_code = error_code;
-       current->thread.trap_no = 13;
+       tsk->thread.error_code = error_code;
+       tsk->thread.trap_no = 13;
 
-       if (show_unhandled_signals && unhandled_signal(current, SIGSEGV) &&
-           printk_ratelimit()) {
+       if (show_unhandled_signals && unhandled_signal(tsk, SIGSEGV) &&
+                       printk_ratelimit()) {
                printk(KERN_INFO
-                   "%s[%d] general protection ip:%lx sp:%lx error:%lx",
-                   current->comm, task_pid_nr(current),
-                   regs->ip, regs->sp, error_code);
+                       "%s[%d] general protection ip:%lx sp:%lx error:%lx",
+                       tsk->comm, task_pid_nr(tsk),
+                       regs->ip, regs->sp, error_code);
                print_vma_addr(" in ", regs->ip);
                printk("\n");
        }
 
-       force_sig(SIGSEGV, current);
+       force_sig(SIGSEGV, tsk);
        return;
 
 gp_in_vm86:
@@ -671,14 +668,15 @@ gp_in_vm86:
        return;
 
 gp_in_kernel:
-       if (!fixup_exception(regs)) {
-               current->thread.error_code = error_code;
-               current->thread.trap_no = 13;
-               if (notify_die(DIE_GPF, "general protection fault", regs,
+       if (fixup_exception(regs))
+               return;
+
+       tsk->thread.error_code = error_code;
+       tsk->thread.trap_no = 13;
+       if (notify_die(DIE_GPF, "general protection fault", regs,
                                error_code, 13, SIGSEGV) == NOTIFY_STOP)
-                       return;
-               die("general protection fault", regs, error_code);
-       }
+               return;
+       die("general protection fault", regs, error_code);
 }
 
 static notrace __kprobes void
@@ -755,9 +753,9 @@ unknown_nmi_error(unsigned char reason, struct pt_regs *regs)
 
 static DEFINE_SPINLOCK(nmi_print_lock);
 
-void notrace __kprobes die_nmi(struct pt_regs *regs, const char *msg)
+void notrace __kprobes die_nmi(char *str, struct pt_regs *regs, int do_panic)
 {
-       if (notify_die(DIE_NMIWATCHDOG, msg, regs, 0, 2, SIGINT) == NOTIFY_STOP)
+       if (notify_die(DIE_NMIWATCHDOG, str, regs, 0, 2, SIGINT) == NOTIFY_STOP)
                return;
 
        spin_lock(&nmi_print_lock);
@@ -766,10 +764,12 @@ void notrace __kprobes die_nmi(struct pt_regs *regs, const char *msg)
        * to get a message out:
        */
        bust_spinlocks(1);
-       printk(KERN_EMERG "%s", msg);
+       printk(KERN_EMERG "%s", str);
        printk(" on CPU%d, ip %08lx, registers:\n",
                smp_processor_id(), regs->ip);
        show_registers(regs);
+       if (do_panic)
+               panic("Non maskable interrupt");
        console_silent();
        spin_unlock(&nmi_print_lock);
        bust_spinlocks(0);
@@ -789,14 +789,17 @@ void notrace __kprobes die_nmi(struct pt_regs *regs, const char *msg)
 static notrace __kprobes void default_do_nmi(struct pt_regs *regs)
 {
        unsigned char reason = 0;
+       int cpu;
+
+       cpu = smp_processor_id();
 
-       /* Only the BSP gets external NMIs from the system: */
-       if (!smp_processor_id())
+       /* Only the BSP gets external NMIs from the system. */
+       if (!cpu)
                reason = get_nmi_reason();
 
        if (!(reason & 0xc0)) {
                if (notify_die(DIE_NMI_IPI, "nmi_ipi", regs, reason, 2, SIGINT)
-                                                       == NOTIFY_STOP)
+                                                               == NOTIFY_STOP)
                        return;
 #ifdef CONFIG_X86_LOCAL_APIC
                /*
@@ -805,7 +808,7 @@ static notrace __kprobes void default_do_nmi(struct pt_regs *regs)
                 */
                if (nmi_watchdog_tick(regs, reason))
                        return;
-               if (!do_nmi_callback(regs, smp_processor_id()))
+               if (!do_nmi_callback(regs, cpu))
                        unknown_nmi_error(reason, regs);
 #else
                unknown_nmi_error(reason, regs);
@@ -815,6 +818,8 @@ static notrace __kprobes void default_do_nmi(struct pt_regs *regs)
        }
        if (notify_die(DIE_NMI, "nmi", regs, reason, 2, SIGINT) == NOTIFY_STOP)
                return;
+
+       /* AK: following checks seem to be broken on modern chipsets. FIXME */
        if (reason & 0x80)
                mem_parity_error(reason, regs);
        if (reason & 0x40)
@@ -826,8 +831,6 @@ static notrace __kprobes void default_do_nmi(struct pt_regs *regs)
        reassert_nmi();
 }
 
-static int ignore_nmis;
-
 notrace __kprobes void do_nmi(struct pt_regs *regs, long error_code)
 {
        int cpu;
@@ -912,7 +915,7 @@ void __kprobes do_debug(struct pt_regs *regs, long error_code)
        tsk->thread.debugctlmsr = 0;
 
        if (notify_die(DIE_DEBUG, "debug", regs, condition, error_code,
-                                       SIGTRAP) == NOTIFY_STOP)
+                                               SIGTRAP) == NOTIFY_STOP)
                return;
        /* It's safe to allow irq's after DR6 has been saved */
        if (regs->flags & X86_EFLAGS_IF)
@@ -973,9 +976,8 @@ clear_TF_reenable:
 void math_error(void __user *ip)
 {
        struct task_struct *task;
-       unsigned short cwd;
-       unsigned short swd;
        siginfo_t info;
+       unsigned short cwd, swd;
 
        /*
         * Save the info for the exception handler and clear the error.
@@ -994,7 +996,7 @@ void math_error(void __user *ip)
         * C1 reg you need in case of a stack fault, 0x040 is the stack
         * fault bit.  We should only be taking one exception at a time,
         * so if this combination doesn't produce any single exception,
-        * then we have a bad program that isn't syncronizing its FPU usage
+        * then we have a bad program that isn't synchronizing its FPU usage
         * and it will suffer the consequences since we won't be able to
         * fully reproduce the context of the exception
         */
@@ -1003,7 +1005,7 @@ void math_error(void __user *ip)
        switch (swd & ~cwd & 0x3f) {
        case 0x000: /* No unmasked exception */
                return;
-       default:    /* Multiple exceptions */
+       default: /* Multiple exceptions */
                break;
        case 0x001: /* Invalid Op */
                /*
@@ -1039,8 +1041,8 @@ void do_coprocessor_error(struct pt_regs *regs, long error_code)
 static void simd_math_error(void __user *ip)
 {
        struct task_struct *task;
-       unsigned short mxcsr;
        siginfo_t info;
+       unsigned short mxcsr;
 
        /*
         * Save the info for the exception handler and clear the error.
@@ -1116,7 +1118,7 @@ void do_spurious_interrupt_bug(struct pt_regs *regs, long error_code)
 
 unsigned long patch_espfix_desc(unsigned long uesp, unsigned long kesp)
 {
-       struct desc_struct *gdt = __get_cpu_var(gdt_page).gdt;
+       struct desc_struct *gdt = get_cpu_gdt_table(smp_processor_id());
        unsigned long base = (kesp - uesp) & -THREAD_SIZE;
        unsigned long new_kesp = kesp - base;
        unsigned long lim_pages = (new_kesp | (THREAD_SIZE - 1)) >> PAGE_SHIFT;
@@ -1195,19 +1197,16 @@ void __init trap_init(void)
        early_iounmap(p, 4);
 #endif
 
-#ifdef CONFIG_X86_LOCAL_APIC
-       init_apic_mappings();
-#endif
-       set_trap_gate(0,  &divide_error);
-       set_intr_gate(1,  &debug);
-       set_intr_gate(2,  &nmi);
-       set_system_intr_gate(3, &int3); /* int3/4 can be called from all */
-       set_system_gate(4, &overflow);
-       set_trap_gate(5,  &bounds);
-       set_trap_gate(6,  &invalid_op);
-       set_trap_gate(7,  &device_not_available);
-       set_task_gate(8,  GDT_ENTRY_DOUBLEFAULT_TSS);
-       set_trap_gate(9,  &coprocessor_segment_overrun);
+       set_trap_gate(0, &divide_error);
+       set_intr_gate(1, &debug);
+       set_intr_gate(2, &nmi);
+       set_system_intr_gate(3, &int3); /* int3 can be called from all */
+       set_system_gate(4, &overflow); /* int4 can be called from all */
+       set_trap_gate(5, &bounds);
+       set_trap_gate(6, &invalid_op);
+       set_trap_gate(7, &device_not_available);
+       set_task_gate(8, GDT_ENTRY_DOUBLEFAULT_TSS);
+       set_trap_gate(9, &coprocessor_segment_overrun);
        set_trap_gate(10, &invalid_TSS);
        set_trap_gate(11, &segment_not_present);
        set_trap_gate(12, &stack_segment);