diff options
| author | Jesse Barnes <jbarnes@virtuousgeek.org> | 2010-08-05 10:22:30 -0400 |
|---|---|---|
| committer | Jason Wessel <jason.wessel@windriver.com> | 2010-08-05 10:22:30 -0400 |
| commit | b45cfba4e9005d64d419718e7ff7f7cab44c1994 (patch) | |
| tree | 2d454a67c9a87ffc01579d958f9d95dd5e13170e | |
| parent | 3fa43aba08c5b5a4b407e402606fbe463239b14a (diff) | |
vt,console,kdb: implement atomic console enter/leave functions
These functions allow the kernel debugger to save and restore the
state of the system console.
Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Signed-off-by: Jason Wessel <jason.wessel@windriver.com>
CC: David Airlie <airlied@linux.ie>
CC: Andrew Morton <akpm@linux-foundation.org>
| -rw-r--r-- | drivers/char/vt.c | 61 | ||||
| -rw-r--r-- | include/linux/console.h | 13 |
2 files changed, 74 insertions, 0 deletions
diff --git a/drivers/char/vt.c b/drivers/char/vt.c index 7cdb6ee569cd..117ce99115dc 100644 --- a/drivers/char/vt.c +++ b/drivers/char/vt.c | |||
| @@ -187,10 +187,15 @@ static DECLARE_WORK(console_work, console_callback); | |||
| 187 | * fg_console is the current virtual console, | 187 | * fg_console is the current virtual console, |
| 188 | * last_console is the last used one, | 188 | * last_console is the last used one, |
| 189 | * want_console is the console we want to switch to, | 189 | * want_console is the console we want to switch to, |
| 190 | * saved_* variants are for save/restore around kernel debugger enter/leave | ||
| 190 | */ | 191 | */ |
| 191 | int fg_console; | 192 | int fg_console; |
| 192 | int last_console; | 193 | int last_console; |
| 193 | int want_console = -1; | 194 | int want_console = -1; |
| 195 | int saved_fg_console; | ||
| 196 | int saved_last_console; | ||
| 197 | int saved_want_console; | ||
| 198 | int saved_vc_mode; | ||
| 194 | 199 | ||
| 195 | /* | 200 | /* |
| 196 | * For each existing display, we have a pointer to console currently visible | 201 | * For each existing display, we have a pointer to console currently visible |
| @@ -3414,6 +3419,62 @@ int con_is_bound(const struct consw *csw) | |||
| 3414 | EXPORT_SYMBOL(con_is_bound); | 3419 | EXPORT_SYMBOL(con_is_bound); |
| 3415 | 3420 | ||
| 3416 | /** | 3421 | /** |
| 3422 | * con_debug_enter - prepare the console for the kernel debugger | ||
| 3423 | * @sw: console driver | ||
| 3424 | * | ||
| 3425 | * Called when the console is taken over by the kernel debugger, this | ||
| 3426 | * function needs to save the current console state, then put the console | ||
| 3427 | * into a state suitable for the kernel debugger. | ||
| 3428 | * | ||
| 3429 | * RETURNS: | ||
| 3430 | * Zero on success, nonzero if a failure occurred when trying to prepare | ||
| 3431 | * the console for the debugger. | ||
| 3432 | */ | ||
| 3433 | int con_debug_enter(struct vc_data *vc) | ||
| 3434 | { | ||
| 3435 | int ret = 0; | ||
| 3436 | |||
| 3437 | saved_fg_console = fg_console; | ||
| 3438 | saved_last_console = last_console; | ||
| 3439 | saved_want_console = want_console; | ||
| 3440 | saved_vc_mode = vc->vc_mode; | ||
| 3441 | vc->vc_mode = KD_TEXT; | ||
| 3442 | console_blanked = 0; | ||
| 3443 | if (vc->vc_sw->con_debug_enter) | ||
| 3444 | ret = vc->vc_sw->con_debug_enter(vc); | ||
| 3445 | return ret; | ||
| 3446 | } | ||
| 3447 | EXPORT_SYMBOL_GPL(con_debug_enter); | ||
| 3448 | |||
| 3449 | /** | ||
| 3450 | * con_debug_leave - restore console state | ||
| 3451 | * @sw: console driver | ||
| 3452 | * | ||
| 3453 | * Restore the console state to what it was before the kernel debugger | ||
| 3454 | * was invoked. | ||
| 3455 | * | ||
| 3456 | * RETURNS: | ||
| 3457 | * Zero on success, nonzero if a failure occurred when trying to restore | ||
| 3458 | * the console. | ||
| 3459 | */ | ||
| 3460 | int con_debug_leave(void) | ||
| 3461 | { | ||
| 3462 | struct vc_data *vc; | ||
| 3463 | int ret = 0; | ||
| 3464 | |||
| 3465 | fg_console = saved_fg_console; | ||
| 3466 | last_console = saved_last_console; | ||
| 3467 | want_console = saved_want_console; | ||
| 3468 | vc_cons[fg_console].d->vc_mode = saved_vc_mode; | ||
| 3469 | |||
| 3470 | vc = vc_cons[fg_console].d; | ||
| 3471 | if (vc->vc_sw->con_debug_leave) | ||
| 3472 | ret = vc->vc_sw->con_debug_leave(vc); | ||
| 3473 | return ret; | ||
| 3474 | } | ||
| 3475 | EXPORT_SYMBOL_GPL(con_debug_leave); | ||
| 3476 | |||
| 3477 | /** | ||
| 3417 | * register_con_driver - register console driver to console layer | 3478 | * register_con_driver - register console driver to console layer |
| 3418 | * @csw: console driver | 3479 | * @csw: console driver |
| 3419 | * @first: the first console to take over, minimum value is 0 | 3480 | * @first: the first console to take over, minimum value is 0 |
diff --git a/include/linux/console.h b/include/linux/console.h index dcca5339ceb3..f76fc297322d 100644 --- a/include/linux/console.h +++ b/include/linux/console.h | |||
| @@ -55,6 +55,16 @@ struct consw { | |||
| 55 | void (*con_invert_region)(struct vc_data *, u16 *, int); | 55 | void (*con_invert_region)(struct vc_data *, u16 *, int); |
| 56 | u16 *(*con_screen_pos)(struct vc_data *, int); | 56 | u16 *(*con_screen_pos)(struct vc_data *, int); |
| 57 | unsigned long (*con_getxy)(struct vc_data *, unsigned long, int *, int *); | 57 | unsigned long (*con_getxy)(struct vc_data *, unsigned long, int *, int *); |
| 58 | /* | ||
| 59 | * Prepare the console for the debugger. This includes, but is not | ||
| 60 | * limited to, unblanking the console, loading an appropriate | ||
| 61 | * palette, and allowing debugger generated output. | ||
| 62 | */ | ||
| 63 | int (*con_debug_enter)(struct vc_data *); | ||
| 64 | /* | ||
| 65 | * Restore the console to its pre-debug state as closely as possible. | ||
| 66 | */ | ||
| 67 | int (*con_debug_leave)(struct vc_data *); | ||
| 58 | }; | 68 | }; |
| 59 | 69 | ||
| 60 | extern const struct consw *conswitchp; | 70 | extern const struct consw *conswitchp; |
| @@ -69,6 +79,9 @@ int register_con_driver(const struct consw *csw, int first, int last); | |||
| 69 | int unregister_con_driver(const struct consw *csw); | 79 | int unregister_con_driver(const struct consw *csw); |
| 70 | int take_over_console(const struct consw *sw, int first, int last, int deflt); | 80 | int take_over_console(const struct consw *sw, int first, int last, int deflt); |
| 71 | void give_up_console(const struct consw *sw); | 81 | void give_up_console(const struct consw *sw); |
| 82 | int con_debug_enter(struct vc_data *vc); | ||
| 83 | int con_debug_leave(void); | ||
| 84 | |||
| 72 | /* scroll */ | 85 | /* scroll */ |
| 73 | #define SM_UP (1) | 86 | #define SM_UP (1) |
| 74 | #define SM_DOWN (2) | 87 | #define SM_DOWN (2) |
