Merge branch 'drm-patches' of master.kernel.org:/pub/scm/linux/kernel/git/airlied...
[linux-drm-fsl-dcu.git] / arch / i386 / kernel / traps.c
index 2b30dbf8d1170167283d57a7cbe3b0099231c788..f21b41e7770c6768c2118ac0449a3f5f8b15397c 100644 (file)
@@ -94,11 +94,7 @@ asmlinkage void spurious_interrupt_bug(void);
 asmlinkage void machine_check(void);
 
 int kstack_depth_to_print = 24;
-#ifdef CONFIG_STACK_UNWIND
-static int call_trace = 1;
-#else
-#define call_trace (-1)
-#endif
+static unsigned int code_bytes = 64;
 ATOMIC_NOTIFIER_HEAD(i386die_chain);
 
 int register_die_notifier(struct notifier_block *nb)
@@ -152,33 +148,6 @@ static inline unsigned long print_context_stack(struct thread_info *tinfo,
        return ebp;
 }
 
-struct ops_and_data {
-       struct stacktrace_ops *ops;
-       void *data;
-};
-
-static asmlinkage int
-dump_trace_unwind(struct unwind_frame_info *info, void *data)
-{
-       struct ops_and_data *oad = (struct ops_and_data *)data;
-       int n = 0;
-       unsigned long sp = UNW_SP(info);
-
-       if (arch_unw_user_mode(info))
-               return -1;
-       while (unwind(info) == 0 && UNW_PC(info)) {
-               n++;
-               oad->ops->address(oad->data, UNW_PC(info));
-               if (arch_unw_user_mode(info))
-                       break;
-               if ((sp & ~(PAGE_SIZE - 1)) == (UNW_SP(info) & ~(PAGE_SIZE - 1))
-                   && sp > UNW_SP(info))
-                       break;
-               sp = UNW_SP(info);
-       }
-       return n;
-}
-
 #define MSG(msg) ops->warning(data, msg)
 
 void dump_trace(struct task_struct *task, struct pt_regs *regs,
@@ -190,41 +159,6 @@ void dump_trace(struct task_struct *task, struct pt_regs *regs,
        if (!task)
                task = current;
 
-       if (call_trace >= 0) {
-               int unw_ret = 0;
-               struct unwind_frame_info info;
-               struct ops_and_data oad = { .ops = ops, .data = data };
-
-               if (regs) {
-                       if (unwind_init_frame_info(&info, task, regs) == 0)
-                               unw_ret = dump_trace_unwind(&info, &oad);
-               } else if (task == current)
-                       unw_ret = unwind_init_running(&info, dump_trace_unwind,
-                                                     &oad);
-               else {
-                       if (unwind_init_blocked(&info, task) == 0)
-                               unw_ret = dump_trace_unwind(&info, &oad);
-               }
-               if (unw_ret > 0) {
-                       if (call_trace == 1 && !arch_unw_user_mode(&info)) {
-                               ops->warning_symbol(data,
-                                            "DWARF2 unwinder stuck at %s",
-                                            UNW_PC(&info));
-                               if (UNW_SP(&info) >= PAGE_OFFSET) {
-                                       MSG("Leftover inexact backtrace:");
-                                       stack = (void *)UNW_SP(&info);
-                                       if (!stack)
-                                               return;
-                                       ebp = UNW_FP(&info);
-                               } else
-                                       MSG("Full inexact backtrace again:");
-                       } else if (call_trace >= 1)
-                               return;
-                       else
-                               MSG("Full inexact backtrace again:");
-               } else
-                       MSG("Inexact backtrace:");
-       }
        if (!stack) {
                unsigned long dummy;
                stack = &dummy;
@@ -358,10 +292,11 @@ void show_registers(struct pt_regs *regs)
        int i;
        int in_kernel = 1;
        unsigned long esp;
-       unsigned short ss;
+       unsigned short ss, gs;
 
        esp = (unsigned long) (&regs->esp);
        savesegment(ss, ss);
+       savesegment(gs, gs);
        if (user_mode_vm(regs)) {
                in_kernel = 0;
                esp = regs->esp;
@@ -380,8 +315,8 @@ void show_registers(struct pt_regs *regs)
                regs->eax, regs->ebx, regs->ecx, regs->edx);
        printk(KERN_EMERG "esi: %08lx   edi: %08lx   ebp: %08lx   esp: %08lx\n",
                regs->esi, regs->edi, regs->ebp, esp);
-       printk(KERN_EMERG "ds: %04x   es: %04x   ss: %04x\n",
-               regs->xds & 0xffff, regs->xes & 0xffff, ss);
+       printk(KERN_EMERG "ds: %04x   es: %04x   fs: %04x  gs: %04x  ss: %04x\n",
+              regs->xds & 0xffff, regs->xes & 0xffff, regs->xfs & 0xffff, gs, ss);
        printk(KERN_EMERG "Process %.*s (pid: %d, ti=%p task=%p task.ti=%p)",
                TASK_COMM_LEN, current->comm, current->pid,
                current_thread_info(), current, current->thread_info);
@@ -391,7 +326,8 @@ void show_registers(struct pt_regs *regs)
         */
        if (in_kernel) {
                u8 *eip;
-               int code_bytes = 64;
+               unsigned int code_prologue = code_bytes * 43 / 64;
+               unsigned int code_len = code_bytes;
                unsigned char c;
 
                printk("\n" KERN_EMERG "Stack: ");
@@ -399,14 +335,14 @@ void show_registers(struct pt_regs *regs)
 
                printk(KERN_EMERG "Code: ");
 
-               eip = (u8 *)regs->eip - 43;
+               eip = (u8 *)regs->eip - code_prologue;
                if (eip < (u8 *)PAGE_OFFSET ||
                        probe_kernel_address(eip, c)) {
                        /* try starting at EIP */
                        eip = (u8 *)regs->eip;
-                       code_bytes = 32;
+                       code_len = code_len - code_prologue + 1;
                }
-               for (i = 0; i < code_bytes; i++, eip++) {
+               for (i = 0; i < code_len; i++, eip++) {
                        if (eip < (u8 *)PAGE_OFFSET ||
                                probe_kernel_address(eip, c)) {
                                printk(" Bad EIP value.");
@@ -540,8 +476,6 @@ static void __kprobes do_trap(int trapnr, int signr, char *str, int vm86,
                              siginfo_t *info)
 {
        struct task_struct *tsk = current;
-       tsk->thread.error_code = error_code;
-       tsk->thread.trap_no = trapnr;
 
        if (regs->eflags & VM_MASK) {
                if (vm86)
@@ -553,6 +487,18 @@ static void __kprobes do_trap(int trapnr, int signr, char *str, int vm86,
                goto kernel_trap;
 
        trap_signal: {
+               /*
+                * We want error_code and trap_no set for userspace faults and
+                * kernelspace faults which result in die(), but not
+                * kernelspace faults which are fixed up.  die() gives the
+                * process no chance to handle the signal and notice the
+                * kernel fault information, so that won't result in polluting
+                * the information about previously queued, but not yet
+                * delivered, faults.  See also do_general_protection below.
+                */
+               tsk->thread.error_code = error_code;
+               tsk->thread.trap_no = trapnr;
+
                if (info)
                        force_sig_info(signr, info, tsk);
                else
@@ -561,8 +507,11 @@ static void __kprobes do_trap(int trapnr, int signr, char *str, int vm86,
        }
 
        kernel_trap: {
-               if (!fixup_exception(regs))
+               if (!fixup_exception(regs)) {
+                       tsk->thread.error_code = error_code;
+                       tsk->thread.trap_no = trapnr;
                        die(str, regs, error_code);
+               }
                return;
        }
 
@@ -647,7 +596,7 @@ fastcall void __kprobes do_general_protection(struct pt_regs * regs,
         * and we set the offset field correctly. Then we let the CPU to
         * restart the faulting instruction.
         */
-       if (tss->io_bitmap_base == INVALID_IO_BITMAP_OFFSET_LAZY &&
+       if (tss->x86_tss.io_bitmap_base == INVALID_IO_BITMAP_OFFSET_LAZY &&
            thread->io_bitmap_ptr) {
                memcpy(tss->io_bitmap, thread->io_bitmap_ptr,
                       thread->io_bitmap_max);
@@ -660,16 +609,13 @@ fastcall void __kprobes do_general_protection(struct pt_regs * regs,
                                thread->io_bitmap_max, 0xff,
                                tss->io_bitmap_max - thread->io_bitmap_max);
                tss->io_bitmap_max = thread->io_bitmap_max;
-               tss->io_bitmap_base = IO_BITMAP_OFFSET;
+               tss->x86_tss.io_bitmap_base = IO_BITMAP_OFFSET;
                tss->io_bitmap_owner = thread;
                put_cpu();
                return;
        }
        put_cpu();
 
-       current->thread.error_code = error_code;
-       current->thread.trap_no = 13;
-
        if (regs->eflags & VM_MASK)
                goto gp_in_vm86;
 
@@ -688,6 +634,8 @@ gp_in_vm86:
 
 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,
                                error_code, 13, SIGSEGV) == NOTIFY_STOP)
                        return;
@@ -1082,9 +1030,7 @@ fastcall void do_spurious_interrupt_bug(struct pt_regs * regs,
 fastcall unsigned long patch_espfix_desc(unsigned long uesp,
                                          unsigned long kesp)
 {
-       int cpu = smp_processor_id();
-       struct Xgt_desc_struct *cpu_gdt_descr = &per_cpu(cpu_gdt_descr, cpu);
-       struct desc_struct *gdt = (struct desc_struct *)cpu_gdt_descr->address;
+       struct desc_struct *gdt = __get_cpu_var(gdt_page).gdt;
        unsigned long base = (kesp - uesp) & -THREAD_SIZE;
        unsigned long new_kesp = kesp - base;
        unsigned long lim_pages = (new_kesp | (THREAD_SIZE - 1)) >> PAGE_SHIFT;
@@ -1259,18 +1205,12 @@ static int __init kstack_setup(char *s)
 }
 __setup("kstack=", kstack_setup);
 
-#ifdef CONFIG_STACK_UNWIND
-static int __init call_trace_setup(char *s)
+static int __init code_bytes_setup(char *s)
 {
-       if (strcmp(s, "old") == 0)
-               call_trace = -1;
-       else if (strcmp(s, "both") == 0)
-               call_trace = 0;
-       else if (strcmp(s, "newfallback") == 0)
-               call_trace = 1;
-       else if (strcmp(s, "new") == 2)
-               call_trace = 2;
+       code_bytes = simple_strtoul(s, NULL, 0);
+       if (code_bytes > 8192)
+               code_bytes = 8192;
+
        return 1;
 }
-__setup("call_trace=", call_trace_setup);
-#endif
+__setup("code_bytes=", code_bytes_setup);