]> rtime.felk.cvut.cz Git - can-eth-gw-linux.git/commitdiff
Merge tag 'for_linus-3.7' of git://git.kernel.org/pub/scm/linux/kernel/git/jwessel...
authorLinus Torvalds <torvalds@linux-foundation.org>
Sat, 13 Oct 2012 02:16:58 +0000 (11:16 +0900)
committerLinus Torvalds <torvalds@linux-foundation.org>
Sat, 13 Oct 2012 02:16:58 +0000 (11:16 +0900)
Pull KGDB/KDB fixes and cleanups from Jason Wessel:
 "Cleanups
   - Clean up compile warnings in kgdboc.c and x86/kernel/kgdb.c
   - Add module event hooks for simplified debugging with gdb
 Fixes
   - Fix kdb to stop paging with 'q' on bta and dmesg
   - Fix for data that scrolls off the vga console due to line wrapping
     when using the kdb pager
 New
   - The debug core registers for kernel module events which allows a
     kernel aware gdb to automatically load symbols and break on entry
     to a kernel module
   - Allow kgdboc=kdb to setup kdb on the vga console"

* tag 'for_linus-3.7' of git://git.kernel.org/pub/scm/linux/kernel/git/jwessel/kgdb:
  tty/console: fix warnings in drivers/tty/serial/kgdboc.c
  kdb,vt_console: Fix missed data due to pager overruns
  kdb: Fix dmesg/bta scroll to quit with 'q'
  kgdboc: Accept either kbd or kdb to activate the vga + keyboard kdb shell
  kgdb,x86: fix warning about unused variable
  mips,kgdb: fix recursive page fault with CONFIG_KPROBES
  kgdb: Add module event hooks

1  2 
drivers/tty/serial/kgdboc.c
drivers/tty/vt/vt.c
kernel/debug/debug_core.c
kernel/debug/kdb/kdb_main.c

index c0b334327d9313e71b099b2ff0667671be417c50,509e71456d139a5a7b750c89bb0402d42943ac10..10020547c60b5735d4cbf667956c911aa06a1030
@@@ -97,7 -97,8 +97,8 @@@ static void kgdboc_restore_input(void
  
  static int kgdboc_register_kbd(char **cptr)
  {
-       if (strncmp(*cptr, "kbd", 3) == 0) {
+       if (strncmp(*cptr, "kbd", 3) == 0 ||
+               strncmp(*cptr, "kdb", 3) == 0) {
                if (kdb_poll_idx < KDB_POLL_FUNC_MAX) {
                        kdb_poll_funcs[kdb_poll_idx] = kdb_get_kbd_char;
                        kdb_poll_idx++;
@@@ -122,7 -123,7 +123,7 @@@ static void kgdboc_unregister_kbd(void
                        i--;
                }
        }
 -      flush_work_sync(&kgdboc_restore_input_work);
 +      flush_work(&kgdboc_restore_input_work);
  }
  #else /* ! CONFIG_KDB_KEYBOARD */
  #define kgdboc_register_kbd(x) 0
@@@ -145,8 -146,6 +146,8 @@@ __setup("kgdboc=", kgdboc_option_setup)
  
  static void cleanup_kgdboc(void)
  {
 +      if (kgdb_unregister_nmi_console())
 +              return;
        kgdboc_unregister_kbd();
        if (configured == 1)
                kgdb_unregister_io_module(&kgdboc_io_ops);
@@@ -200,18 -199,11 +201,18 @@@ do_register
        if (err)
                goto noconfig;
  
 +      err = kgdb_register_nmi_console();
 +      if (err)
 +              goto nmi_con_failed;
 +
        configured = 1;
  
        return 0;
  
 +nmi_con_failed:
 +      kgdb_unregister_io_module(&kgdboc_io_ops);
  noconfig:
 +      kgdboc_unregister_kbd();
        config[0] = 0;
        configured = 0;
        cleanup_kgdboc();
diff --combined drivers/tty/vt/vt.c
index 999ca63afdeffc2c03a0d5a057d57653f3b85490,a13f7e158c5b49e31ae0e8dee008f54ad6bde4de..f87d7e8964bf0849c1ab3e3da327e3a14c9b35a2
@@@ -537,27 -537,45 +537,27 @@@ void complement_pos(struct vc_data *vc
  
  static void insert_char(struct vc_data *vc, unsigned int nr)
  {
 -      unsigned short *p, *q = (unsigned short *)vc->vc_pos;
 +      unsigned short *p = (unsigned short *) vc->vc_pos;
  
 -      p = q + vc->vc_cols - nr - vc->vc_x;
 -      while (--p >= q)
 -              scr_writew(scr_readw(p), p + nr);
 -      scr_memsetw(q, vc->vc_video_erase_char, nr * 2);
 +      scr_memmovew(p + nr, p, vc->vc_cols - vc->vc_x);
 +      scr_memsetw(p, vc->vc_video_erase_char, nr * 2);
        vc->vc_need_wrap = 0;
 -      if (DO_UPDATE(vc)) {
 -              unsigned short oldattr = vc->vc_attr;
 -              vc->vc_sw->con_bmove(vc, vc->vc_y, vc->vc_x, vc->vc_y, vc->vc_x + nr, 1,
 -                                   vc->vc_cols - vc->vc_x - nr);
 -              vc->vc_attr = vc->vc_video_erase_char >> 8;
 -              while (nr--)
 -                      vc->vc_sw->con_putc(vc, vc->vc_video_erase_char, vc->vc_y, vc->vc_x + nr);
 -              vc->vc_attr = oldattr;
 -      }
 +      if (DO_UPDATE(vc))
 +              do_update_region(vc, (unsigned long) p,
 +                      (vc->vc_cols - vc->vc_x) / 2 + 1);
  }
  
  static void delete_char(struct vc_data *vc, unsigned int nr)
  {
 -      unsigned int i = vc->vc_x;
 -      unsigned short *p = (unsigned short *)vc->vc_pos;
 +      unsigned short *p = (unsigned short *) vc->vc_pos;
  
 -      while (++i <= vc->vc_cols - nr) {
 -              scr_writew(scr_readw(p+nr), p);
 -              p++;
 -      }
 -      scr_memsetw(p, vc->vc_video_erase_char, nr * 2);
 +      scr_memcpyw(p, p + nr, vc->vc_cols - vc->vc_x - nr);
 +      scr_memsetw(p + vc->vc_cols - vc->vc_x - nr, vc->vc_video_erase_char,
 +                      nr * 2);
        vc->vc_need_wrap = 0;
 -      if (DO_UPDATE(vc)) {
 -              unsigned short oldattr = vc->vc_attr;
 -              vc->vc_sw->con_bmove(vc, vc->vc_y, vc->vc_x + nr, vc->vc_y, vc->vc_x, 1,
 -                                   vc->vc_cols - vc->vc_x - nr);
 -              vc->vc_attr = vc->vc_video_erase_char >> 8;
 -              while (nr--)
 -                      vc->vc_sw->con_putc(vc, vc->vc_video_erase_char, vc->vc_y,
 -                                   vc->vc_cols - 1 - nr);
 -              vc->vc_attr = oldattr;
 -      }
 +      if (DO_UPDATE(vc))
 +              do_update_region(vc, (unsigned long) p,
 +                      (vc->vc_cols - vc->vc_x) / 2);
  }
  
  static int softcursor_original;
@@@ -1154,26 -1172,45 +1154,26 @@@ static void csi_J(struct vc_data *vc, i
                case 0: /* erase from cursor to end of display */
                        count = (vc->vc_scr_end - vc->vc_pos) >> 1;
                        start = (unsigned short *)vc->vc_pos;
 -                      if (DO_UPDATE(vc)) {
 -                              /* do in two stages */
 -                              vc->vc_sw->con_clear(vc, vc->vc_y, vc->vc_x, 1,
 -                                            vc->vc_cols - vc->vc_x);
 -                              vc->vc_sw->con_clear(vc, vc->vc_y + 1, 0,
 -                                            vc->vc_rows - vc->vc_y - 1,
 -                                            vc->vc_cols);
 -                      }
                        break;
                case 1: /* erase from start to cursor */
                        count = ((vc->vc_pos - vc->vc_origin) >> 1) + 1;
                        start = (unsigned short *)vc->vc_origin;
 -                      if (DO_UPDATE(vc)) {
 -                              /* do in two stages */
 -                              vc->vc_sw->con_clear(vc, 0, 0, vc->vc_y,
 -                                            vc->vc_cols);
 -                              vc->vc_sw->con_clear(vc, vc->vc_y, 0, 1,
 -                                            vc->vc_x + 1);
 -                      }
                        break;
                case 3: /* erase scroll-back buffer (and whole display) */
                        scr_memsetw(vc->vc_screenbuf, vc->vc_video_erase_char,
                                    vc->vc_screenbuf_size >> 1);
                        set_origin(vc);
 -                      if (CON_IS_VISIBLE(vc))
 -                              update_screen(vc);
                        /* fall through */
                case 2: /* erase whole display */
                        count = vc->vc_cols * vc->vc_rows;
                        start = (unsigned short *)vc->vc_origin;
 -                      if (DO_UPDATE(vc))
 -                              vc->vc_sw->con_clear(vc, 0, 0,
 -                                            vc->vc_rows,
 -                                            vc->vc_cols);
                        break;
                default:
                        return;
        }
        scr_memsetw(start, vc->vc_video_erase_char, 2 * count);
 +      if (DO_UPDATE(vc))
 +              do_update_region(vc, (unsigned long) start, count);
        vc->vc_need_wrap = 0;
  }
  
@@@ -1186,22 -1223,29 +1186,22 @@@ static void csi_K(struct vc_data *vc, i
                case 0: /* erase from cursor to end of line */
                        count = vc->vc_cols - vc->vc_x;
                        start = (unsigned short *)vc->vc_pos;
 -                      if (DO_UPDATE(vc))
 -                              vc->vc_sw->con_clear(vc, vc->vc_y, vc->vc_x, 1,
 -                                                   vc->vc_cols - vc->vc_x);
                        break;
                case 1: /* erase from start of line to cursor */
                        start = (unsigned short *)(vc->vc_pos - (vc->vc_x << 1));
                        count = vc->vc_x + 1;
 -                      if (DO_UPDATE(vc))
 -                              vc->vc_sw->con_clear(vc, vc->vc_y, 0, 1,
 -                                                   vc->vc_x + 1);
                        break;
                case 2: /* erase whole line */
                        start = (unsigned short *)(vc->vc_pos - (vc->vc_x << 1));
                        count = vc->vc_cols;
 -                      if (DO_UPDATE(vc))
 -                              vc->vc_sw->con_clear(vc, vc->vc_y, 0, 1,
 -                                            vc->vc_cols);
                        break;
                default:
                        return;
        }
        scr_memsetw(start, vc->vc_video_erase_char, 2 * count);
        vc->vc_need_wrap = 0;
 +      if (DO_UPDATE(vc))
 +              do_update_region(vc, (unsigned long) start, count);
  }
  
  static void csi_X(struct vc_data *vc, int vpar) /* erase the following vpar positions */
@@@ -1336,7 -1380,7 +1336,7 @@@ static void respond_string(const char *
                tty_insert_flip_char(tty, *p, 0);
                p++;
        }
 -      con_schedule_flip(tty);
 +      tty_schedule_flip(tty);
  }
  
  static void cursor_report(struct vc_data *vc, struct tty_struct *tty)
@@@ -2748,52 -2792,41 +2748,52 @@@ static void con_flush_chars(struct tty_
  /*
   * Allocate the console screen memory.
   */
 -static int con_open(struct tty_struct *tty, struct file *filp)
 +static int con_install(struct tty_driver *driver, struct tty_struct *tty)
  {
        unsigned int currcons = tty->index;
 -      int ret = 0;
 +      struct vc_data *vc;
 +      int ret;
  
        console_lock();
 -      if (tty->driver_data == NULL) {
 -              ret = vc_allocate(currcons);
 -              if (ret == 0) {
 -                      struct vc_data *vc = vc_cons[currcons].d;
 +      ret = vc_allocate(currcons);
 +      if (ret)
 +              goto unlock;
  
 -                      /* Still being freed */
 -                      if (vc->port.tty) {
 -                              console_unlock();
 -                              return -ERESTARTSYS;
 -                      }
 -                      tty->driver_data = vc;
 -                      vc->port.tty = tty;
 +      vc = vc_cons[currcons].d;
  
 -                      if (!tty->winsize.ws_row && !tty->winsize.ws_col) {
 -                              tty->winsize.ws_row = vc_cons[currcons].d->vc_rows;
 -                              tty->winsize.ws_col = vc_cons[currcons].d->vc_cols;
 -                      }
 -                      if (vc->vc_utf)
 -                              tty->termios->c_iflag |= IUTF8;
 -                      else
 -                              tty->termios->c_iflag &= ~IUTF8;
 -                      console_unlock();
 -                      return ret;
 -              }
 +      /* Still being freed */
 +      if (vc->port.tty) {
 +              ret = -ERESTARTSYS;
 +              goto unlock;
        }
 +
 +      ret = tty_port_install(&vc->port, driver, tty);
 +      if (ret)
 +              goto unlock;
 +
 +      tty->driver_data = vc;
 +      vc->port.tty = tty;
 +
 +      if (!tty->winsize.ws_row && !tty->winsize.ws_col) {
 +              tty->winsize.ws_row = vc_cons[currcons].d->vc_rows;
 +              tty->winsize.ws_col = vc_cons[currcons].d->vc_cols;
 +      }
 +      if (vc->vc_utf)
 +              tty->termios.c_iflag |= IUTF8;
 +      else
 +              tty->termios.c_iflag &= ~IUTF8;
 +unlock:
        console_unlock();
        return ret;
  }
  
 +static int con_open(struct tty_struct *tty, struct file *filp)
 +{
 +      /* everything done in install */
 +      return 0;
 +}
 +
 +
  static void con_close(struct tty_struct *tty, struct file *filp)
  {
        /* Nothing to do - we defer to shutdown */
@@@ -2806,6 -2839,7 +2806,6 @@@ static void con_shutdown(struct tty_str
        console_lock();
        vc->port.tty = NULL;
        console_unlock();
 -      tty_shutdown(tty);
  }
  
  static int default_italic_color    = 2; // green (ASCII)
@@@ -2913,7 -2947,6 +2913,7 @@@ static int __init con_init(void
  console_initcall(con_init);
  
  static const struct tty_operations con_ops = {
 +      .install = con_install,
        .open = con_open,
        .close = con_close,
        .write = con_write,
@@@ -3442,6 -3475,19 +3442,19 @@@ int con_debug_enter(struct vc_data *vc
                        kdb_set(2, setargs);
                }
        }
+       if (vc->vc_cols < 999) {
+               int colcount;
+               char cols[4];
+               const char *setargs[3] = {
+                       "set",
+                       "COLUMNS",
+                       cols,
+               };
+               if (kdbgetintenv(setargs[0], &colcount)) {
+                       snprintf(cols, 4, "%i", vc->vc_cols);
+                       kdb_set(2, setargs);
+               }
+       }
  #endif /* CONFIG_KGDB_KDB */
        return ret;
  }
index 17e073c309e64a907bdd512c16ae19977223594c,8bfa373cd5fdfdb2a0bcc88819898751b4876a15..9a61738cefc8828c310618cd9dc6bd1d0ec44959
@@@ -672,10 -672,6 +672,10 @@@ kgdb_handle_exception(int evector, int 
  {
        struct kgdb_state kgdb_var;
        struct kgdb_state *ks = &kgdb_var;
 +      int ret = 0;
 +
 +      if (arch_kgdb_ops.enable_nmi)
 +              arch_kgdb_ops.enable_nmi(0);
  
        ks->cpu                 = raw_smp_processor_id();
        ks->ex_vector           = evector;
        ks->linux_regs          = regs;
  
        if (kgdb_reenter_check(ks))
 -              return 0; /* Ouch, double exception ! */
 +              goto out; /* Ouch, double exception ! */
        if (kgdb_info[ks->cpu].enter_kgdb != 0)
 -              return 0;
 +              goto out;
  
 -      return kgdb_cpu_enter(ks, regs, DCPU_WANT_MASTER);
 +      ret = kgdb_cpu_enter(ks, regs, DCPU_WANT_MASTER);
 +out:
 +      if (arch_kgdb_ops.enable_nmi)
 +              arch_kgdb_ops.enable_nmi(1);
 +      return ret;
  }
  
+ /*
+  * GDB places a breakpoint at this function to know dynamically
+  * loaded objects. It's not defined static so that only one instance with this
+  * name exists in the kernel.
+  */
+ static int module_event(struct notifier_block *self, unsigned long val,
+       void *data)
+ {
+       return 0;
+ }
+ static struct notifier_block dbg_module_load_nb = {
+       .notifier_call  = module_event,
+ };
  int kgdb_nmicallback(int cpu, void *regs)
  {
  #ifdef CONFIG_SMP
@@@ -824,6 -832,7 +840,7 @@@ static void kgdb_register_callbacks(voi
                kgdb_arch_init();
                if (!dbg_is_early)
                        kgdb_arch_late();
+               register_module_notifier(&dbg_module_load_nb);
                register_reboot_notifier(&dbg_reboot_notifier);
                atomic_notifier_chain_register(&panic_notifier_list,
                                               &kgdb_panic_event_nb);
@@@ -847,6 -856,7 +864,7 @@@ static void kgdb_unregister_callbacks(v
        if (kgdb_io_module_registered) {
                kgdb_io_module_registered = 0;
                unregister_reboot_notifier(&dbg_reboot_notifier);
+               unregister_module_notifier(&dbg_module_load_nb);
                atomic_notifier_chain_unregister(&panic_notifier_list,
                                               &kgdb_panic_event_nb);
                kgdb_arch_exit();
index 1261dc7eaeb9723dd0f14349d17581a6936a80a8,1afeb5c1e5a92e81d8b60599448cab871ed67698..4d5f8d5612f349389fee0c22442267b6545c3931
@@@ -21,7 -21,6 +21,7 @@@
  #include <linux/smp.h>
  #include <linux/utsname.h>
  #include <linux/vmalloc.h>
 +#include <linux/atomic.h>
  #include <linux/module.h>
  #include <linux/mm.h>
  #include <linux/init.h>
@@@ -2101,6 -2100,8 +2101,8 @@@ static int kdb_dmesg(int argc, const ch
                }
                if (!lines--)
                        break;
+               if (KDB_FLAG(CMD_INTERRUPT))
+                       return 0;
  
                kdb_printf("%.*s\n", (int)len - 1, buf);
        }
        return 0;
  }
  #endif /* CONFIG_PRINTK */
 +
 +/* Make sure we balance enable/disable calls, must disable first. */
 +static atomic_t kdb_nmi_disabled;
 +
 +static int kdb_disable_nmi(int argc, const char *argv[])
 +{
 +      if (atomic_read(&kdb_nmi_disabled))
 +              return 0;
 +      atomic_set(&kdb_nmi_disabled, 1);
 +      arch_kgdb_ops.enable_nmi(0);
 +      return 0;
 +}
 +
 +static int kdb_param_enable_nmi(const char *val, const struct kernel_param *kp)
 +{
 +      if (!atomic_add_unless(&kdb_nmi_disabled, -1, 0))
 +              return -EINVAL;
 +      arch_kgdb_ops.enable_nmi(1);
 +      return 0;
 +}
 +
 +static const struct kernel_param_ops kdb_param_ops_enable_nmi = {
 +      .set = kdb_param_enable_nmi,
 +};
 +module_param_cb(enable_nmi, &kdb_param_ops_enable_nmi, NULL, 0600);
 +
  /*
   * kdb_cpu - This function implements the 'cpu' command.
   *    cpu     [<cpunum>]
@@@ -2878,10 -2853,6 +2880,10 @@@ static void __init kdb_inittab(void
        kdb_register_repeat("dmesg", kdb_dmesg, "[lines]",
          "Display syslog buffer", 0, KDB_REPEAT_NONE);
  #endif
 +      if (arch_kgdb_ops.enable_nmi) {
 +              kdb_register_repeat("disable_nmi", kdb_disable_nmi, "",
 +                "Disable NMI entry to KDB", 0, KDB_REPEAT_NONE);
 +      }
        kdb_register_repeat("defcmd", kdb_defcmd, "name \"usage\" \"help\"",
          "Define a set of commands, down to endefcmd", 0, KDB_REPEAT_NONE);
        kdb_register_repeat("kill", kdb_kill, "<-signal> <pid>",