diff options
Diffstat (limited to 'drivers/char/vt.c')
-rw-r--r-- | drivers/char/vt.c | 121 |
1 files changed, 105 insertions, 16 deletions
diff --git a/drivers/char/vt.c b/drivers/char/vt.c index 7cdb6ee569c..c734f9b1263 100644 --- a/drivers/char/vt.c +++ b/drivers/char/vt.c @@ -104,6 +104,8 @@ #include <linux/io.h> #include <asm/system.h> #include <linux/uaccess.h> +#include <linux/kdb.h> +#include <linux/ctype.h> #define MAX_NR_CON_DRIVER 16 @@ -187,10 +189,15 @@ static DECLARE_WORK(console_work, console_callback); * fg_console is the current virtual console, * last_console is the last used one, * want_console is the console we want to switch to, + * saved_* variants are for save/restore around kernel debugger enter/leave */ int fg_console; int last_console; int want_console = -1; +int saved_fg_console; +int saved_last_console; +int saved_want_console; +int saved_vc_mode; /* * For each existing display, we have a pointer to console currently visible @@ -280,8 +287,12 @@ static inline unsigned short *screenpos(struct vc_data *vc, int offset, int view return p; } +/* Called from the keyboard irq path.. */ static inline void scrolldelta(int lines) { + /* FIXME */ + /* scrolldelta needs some kind of consistency lock, but the BKL was + and still is not protecting versus the scheduled back end */ scrollback_delta += lines; schedule_console_callback(); } @@ -698,7 +709,10 @@ void redraw_screen(struct vc_data *vc, int is_switch) update_attr(vc); clear_buffer_attributes(vc); } - if (update && vc->vc_mode != KD_GRAPHICS) + + /* Forcibly update if we're panicing */ + if ((update && vc->vc_mode != KD_GRAPHICS) || + vt_force_oops_output(vc)) do_update_region(vc, vc->vc_origin, vc->vc_screenbuf_size / 2); } set_cursor(vc); @@ -736,6 +750,7 @@ static void visual_init(struct vc_data *vc, int num, int init) vc->vc_hi_font_mask = 0; vc->vc_complement_mask = 0; vc->vc_can_do_color = 0; + vc->vc_panic_force_write = false; vc->vc_sw->con_init(vc, init); if (!vc->vc_complement_mask) vc->vc_complement_mask = vc->vc_can_do_color ? 0x7700 : 0x0800; @@ -768,6 +783,7 @@ int vc_allocate(unsigned int currcons) /* return 0 on success */ if (!vc) return -ENOMEM; vc_cons[currcons].d = vc; + tty_port_init(&vc->port); INIT_WORK(&vc_cons[currcons].SAK_work, vc_SAK); visual_init(vc, currcons, 1); if (!*vc->vc_uni_pagedir_loc) @@ -831,9 +847,10 @@ static int vc_do_resize(struct tty_struct *tty, struct vc_data *vc, unsigned int cols, unsigned int lines) { unsigned long old_origin, new_origin, new_scr_end, rlth, rrem, err = 0; + unsigned long end; unsigned int old_cols, old_rows, old_row_size, old_screen_size; unsigned int new_cols, new_rows, new_row_size, new_screen_size; - unsigned int end, user; + unsigned int user; unsigned short *newscreen; WARN_CONSOLE_UNLOCKED(); @@ -956,12 +973,12 @@ static int vc_do_resize(struct tty_struct *tty, struct vc_data *vc, * Resize a virtual console as seen from the console end of things. We * use the common vc_do_resize methods to update the structures. The * caller must hold the console sem to protect console internals and - * vc->vc_tty + * vc->port.tty */ int vc_resize(struct vc_data *vc, unsigned int cols, unsigned int rows) { - return vc_do_resize(vc->vc_tty, vc, cols, rows); + return vc_do_resize(vc->port.tty, vc, cols, rows); } /** @@ -1789,8 +1806,8 @@ static void do_con_trol(struct tty_struct *tty, struct vc_data *vc, int c) vc->vc_state = ESnormal; return; case ESpalette: - if ( (c>='0'&&c<='9') || (c>='A'&&c<='F') || (c>='a'&&c<='f') ) { - vc->vc_par[vc->vc_npar++] = (c > '9' ? (c & 0xDF) - 'A' + 10 : c - '0'); + if (isxdigit(c)) { + vc->vc_par[vc->vc_npar++] = hex_to_bin(c); if (vc->vc_npar == 7) { int i = vc->vc_par[0] * 3, j = 1; vc->vc_palette[i] = 16 * vc->vc_par[j++]; @@ -2498,7 +2515,7 @@ static void vt_console_print(struct console *co, const char *b, unsigned count) goto quit; } - if (vc->vc_mode != KD_TEXT) + if (vc->vc_mode != KD_TEXT && !vt_force_oops_output(vc)) goto quit; /* undraw cursor first */ @@ -2604,8 +2621,6 @@ int tioclinux(struct tty_struct *tty, unsigned long arg) return -EFAULT; ret = 0; - lock_kernel(); - switch (type) { case TIOCL_SETSEL: @@ -2680,7 +2695,6 @@ int tioclinux(struct tty_struct *tty, unsigned long arg) ret = -EINVAL; break; } - unlock_kernel(); return ret; } @@ -2793,12 +2807,12 @@ static int con_open(struct tty_struct *tty, struct file *filp) struct vc_data *vc = vc_cons[currcons].d; /* Still being freed */ - if (vc->vc_tty) { + if (vc->port.tty) { release_console_sem(); return -ERESTARTSYS; } tty->driver_data = vc; - vc->vc_tty = tty; + vc->port.tty = tty; if (!tty->winsize.ws_row && !tty->winsize.ws_col) { tty->winsize.ws_row = vc_cons[currcons].d->vc_rows; @@ -2826,7 +2840,7 @@ static void con_shutdown(struct tty_struct *tty) struct vc_data *vc = tty->driver_data; BUG_ON(vc == NULL); acquire_console_sem(); - vc->vc_tty = NULL; + vc->port.tty = NULL; release_console_sem(); tty_shutdown(tty); } @@ -2908,6 +2922,7 @@ static int __init con_init(void) for (currcons = 0; currcons < MIN_NR_CONSOLES; currcons++) { vc_cons[currcons].d = vc = kzalloc(sizeof(struct vc_data), GFP_NOWAIT); INIT_WORK(&vc_cons[currcons].SAK_work, vc_SAK); + tty_port_init(&vc->port); visual_init(vc, currcons, 1); vc->vc_screenbuf = kzalloc(vc->vc_screenbuf_size, GFP_NOWAIT); vc_init(vc, vc->vc_rows, vc->vc_cols, @@ -3059,7 +3074,8 @@ static int bind_con_driver(const struct consw *csw, int first, int last, old_was_color = vc->vc_can_do_color; vc->vc_sw->con_deinit(vc); - vc->vc_origin = (unsigned long)vc->vc_screenbuf; + if (!vc->vc_origin) + vc->vc_origin = (unsigned long)vc->vc_screenbuf; visual_init(vc, i, 0); set_origin(vc); update_attr(vc); @@ -3414,6 +3430,78 @@ int con_is_bound(const struct consw *csw) EXPORT_SYMBOL(con_is_bound); /** + * con_debug_enter - prepare the console for the kernel debugger + * @sw: console driver + * + * Called when the console is taken over by the kernel debugger, this + * function needs to save the current console state, then put the console + * into a state suitable for the kernel debugger. + * + * RETURNS: + * Zero on success, nonzero if a failure occurred when trying to prepare + * the console for the debugger. + */ +int con_debug_enter(struct vc_data *vc) +{ + int ret = 0; + + saved_fg_console = fg_console; + saved_last_console = last_console; + saved_want_console = want_console; + saved_vc_mode = vc->vc_mode; + vc->vc_mode = KD_TEXT; + console_blanked = 0; + if (vc->vc_sw->con_debug_enter) + ret = vc->vc_sw->con_debug_enter(vc); +#ifdef CONFIG_KGDB_KDB + /* Set the initial LINES variable if it is not already set */ + if (vc->vc_rows < 999) { + int linecount; + char lns[4]; + const char *setargs[3] = { + "set", + "LINES", + lns, + }; + if (kdbgetintenv(setargs[0], &linecount)) { + snprintf(lns, 4, "%i", vc->vc_rows); + kdb_set(2, setargs); + } + } +#endif /* CONFIG_KGDB_KDB */ + return ret; +} +EXPORT_SYMBOL_GPL(con_debug_enter); + +/** + * con_debug_leave - restore console state + * @sw: console driver + * + * Restore the console state to what it was before the kernel debugger + * was invoked. + * + * RETURNS: + * Zero on success, nonzero if a failure occurred when trying to restore + * the console. + */ +int con_debug_leave(void) +{ + struct vc_data *vc; + int ret = 0; + + fg_console = saved_fg_console; + last_console = saved_last_console; + want_console = saved_want_console; + vc_cons[fg_console].d->vc_mode = saved_vc_mode; + + vc = vc_cons[fg_console].d; + if (vc->vc_sw->con_debug_leave) + ret = vc->vc_sw->con_debug_leave(vc); + return ret; +} +EXPORT_SYMBOL_GPL(con_debug_leave); + +/** * register_con_driver - register console driver to console layer * @csw: console driver * @first: the first console to take over, minimum value is 0 @@ -3703,7 +3791,8 @@ void do_unblank_screen(int leaving_gfx) return; } vc = vc_cons[fg_console].d; - if (vc->vc_mode != KD_TEXT) + /* Try to unblank in oops case too */ + if (vc->vc_mode != KD_TEXT && !vt_force_oops_output(vc)) return; /* but leave console_blanked != 0 */ if (blankinterval) { @@ -3712,7 +3801,7 @@ void do_unblank_screen(int leaving_gfx) } console_blanked = 0; - if (vc->vc_sw->con_blank(vc, 0, leaving_gfx)) + if (vc->vc_sw->con_blank(vc, 0, leaving_gfx) || vt_force_oops_output(vc)) /* Low-level driver cannot restore -> do it ourselves */ update_screen(vc); if (console_blank_hook) |