[PATCH 33/40] kms,kdb: Force unblank a console device

From: Jason Wessel
Date: Thu Jan 14 2010 - 10:01:43 EST


The kgdboc pre exception handler must atomically save the state of the
existing VC console and activate it, if it is blanked.

Before restoring the kernel to a running state, the kgdboc post
exception handler will restore the state of the VC variables that got
changed while atomic.

Helper macros were added to allow kms code to declare debugger safe
mutexes which can be used so long as the debugger restores the state
before resuming.

CC: David Airlie <airlied@xxxxxxxx>
CC: Jesse Barnes <jbarnes@xxxxxxxxxxxxxxxx>
Signed-off-by: Jason Wessel <jason.wessel@xxxxxxxxxxxxx>
---
drivers/serial/kgdboc.c | 26 ++++++++++++----
drivers/video/console/fbcon.c | 7 ++++
include/linux/kgdb.h | 19 ++++++++++++
kernel/debug/Makefile | 1 +
kernel/debug/debug_core.c | 1 +
kernel/debug/kms_hooks.c | 62 +++++++++++++++++++++++++++++++++++++++++
6 files changed, 109 insertions(+), 7 deletions(-)
create mode 100644 kernel/debug/kms_hooks.c

diff --git a/drivers/serial/kgdboc.c b/drivers/serial/kgdboc.c
index 93b18f9..05d1605 100644
--- a/drivers/serial/kgdboc.c
+++ b/drivers/serial/kgdboc.c
@@ -204,13 +204,19 @@ static int param_set_kgdboc_var(const char *kmessage, struct kernel_param *kp)
return configure_kgdboc();
}

+static int dbg_restore_graphics;
+
static void kgdboc_pre_exp_handler(void)
{
- if (kgdboc_use_kms && dbg_kms_console_core &&
- dbg_kms_console_core->activate_console)
- if (dbg_kms_console_core->activate_console(dbg_kms_console_core))
+ if (!dbg_restore_graphics && kgdboc_use_kms && dbg_kms_console_core &&
+ dbg_kms_console_core->activate_console) {
+ if (dbg_kms_console_core->activate_console(dbg_kms_console_core)) {
printk(KERN_ERR "kgdboc: kernel mode switch error\n");
-
+ } else {
+ dbg_restore_graphics = 1;
+ dbg_pre_vt_hook();
+ }
+ }
/* Increment the module count when the debugger is active */
if (!kgdb_connected)
try_module_get(THIS_MODULE);
@@ -222,9 +228,15 @@ static void kgdboc_post_exp_handler(void)
if (!kgdb_connected)
module_put(THIS_MODULE);
if (kgdboc_use_kms && dbg_kms_console_core &&
- dbg_kms_console_core->restore_console)
- if (dbg_kms_console_core->restore_console(dbg_kms_console_core))
- printk(KERN_ERR "kgdboc: graphics restore failed\n");
+ dbg_kms_console_core->restore_console) {
+ if (dbg_restore_graphics) {
+ if (dbg_kms_console_core->restore_console(dbg_kms_console_core))
+ printk(KERN_ERR "kgdboc: graphics restore failed\n");
+ dbg_restore_graphics = 0;
+ dbg_post_vt_hook();
+ }
+ }
+
#ifdef CONFIG_KDB_KEYBOARD
/* If using the kdb keyboard driver release all the keys. */
if (kgdboc_use_kbd)
diff --git a/drivers/video/console/fbcon.c b/drivers/video/console/fbcon.c
index 3681c6a..6f2ed5a 100644
--- a/drivers/video/console/fbcon.c
+++ b/drivers/video/console/fbcon.c
@@ -75,6 +75,7 @@
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/crc32.h> /* For counting font checksums */
+#include <linux/kgdb.h>
#include <asm/fb.h>
#include <asm/irq.h>
#include <asm/system.h>
@@ -2318,6 +2319,12 @@ static int fbcon_blank(struct vc_data *vc, int blank, int mode_switch)
}
}

+ if (in_dbg_master()) {
+ if (info->fbops->fb_blank)
+ info->fbops->fb_blank(blank, info);
+ return 0;
+ }
+
if (!fbcon_is_inactive(vc, info)) {
if (ops->blank_state != blank) {
ops->blank_state = blank;
diff --git a/include/linux/kgdb.h b/include/linux/kgdb.h
index 68fa243..df67f05 100644
--- a/include/linux/kgdb.h
+++ b/include/linux/kgdb.h
@@ -288,6 +288,14 @@ extern void __init early_kgdboc_init(void);
#endif /* CONFIG_KGDB */

/* Common to all that include kgdb.h */
+#ifdef CONFIG_VT
+extern void dbg_pre_vt_hook(void);
+extern void dbg_post_vt_hook(void);
+#else /* ! CONFIG_VT */
+#define dbg_pre_vt_hook()
+#define dbg_post_vt_hook()
+#endif /* CONFIG_VT */
+
struct dbg_kms_console_ops {
int (*activate_console) (struct dbg_kms_console_ops *ops);
int (*restore_console) (struct dbg_kms_console_ops *ops);
@@ -297,6 +305,14 @@ struct dbg_kms_console_ops {
extern struct dbg_kms_console_ops *dbg_kms_console_core;
extern int dbg_kms_console_ops_register(struct dbg_kms_console_ops *ops);
extern int dbg_kms_console_ops_unregister(struct dbg_kms_console_ops *ops);
+#define in_dbg_master() \
+ (raw_smp_processor_id() == atomic_read(&kgdb_active))
+#define dbg_safe_mutex_lock(x) \
+ if (!in_dbg_master()) \
+ mutex_lock(x)
+#define dbg_safe_mutex_unlock(x) \
+ if (!in_dbg_master()) \
+ mutex_unlock(x)
#else /* ! CONFIG_KGDB */
static inline int dbg_kms_console_ops_register(struct dbg_kms_console_ops *ops)
{
@@ -306,5 +322,8 @@ static inline int dbg_kms_console_ops_unregister(struct dbg_kms_console_ops *ops
{
return 0;
}
+#define in_dbg_master() (0)
+#define dbg_safe_mutex_lock(x) mutex_lock(x)
+#define dbg_safe_mutex_unlock(x) mutex_unlock(x)
#endif /* ! CONFIG_KGDB */
#endif /* _KGDB_H_ */
diff --git a/kernel/debug/Makefile b/kernel/debug/Makefile
index c72de00..fe342c0 100644
--- a/kernel/debug/Makefile
+++ b/kernel/debug/Makefile
@@ -3,5 +3,6 @@
#

obj-$(CONFIG_KGDB) += debug_core.o gdbstub.o
+obj-$(CONFIG_VT) += kms_hooks.o
obj-$(CONFIG_KGDB_KDB) += kdb/

diff --git a/kernel/debug/debug_core.c b/kernel/debug/debug_core.c
index 82c7c47..6ca3f7c 100644
--- a/kernel/debug/debug_core.c
+++ b/kernel/debug/debug_core.c
@@ -106,6 +106,7 @@ static struct kgdb_bkpt kgdb_break[KGDB_MAX_BREAKPOINTS] = {
* The CPU# of the active CPU, or -1 if none:
*/
atomic_t kgdb_active = ATOMIC_INIT(-1);
+EXPORT_SYMBOL_GPL(kgdb_active);

/*
* We use NR_CPUs not PERCPU, in case kgdb is used to debug early
diff --git a/kernel/debug/kms_hooks.c b/kernel/debug/kms_hooks.c
new file mode 100644
index 0000000..c56b7ce
--- /dev/null
+++ b/kernel/debug/kms_hooks.c
@@ -0,0 +1,62 @@
+/*
+ * Created by: Jason Wessel <jason.wessel@xxxxxxxxxxxxx>
+ *
+ * Copyright (c) 2009 Wind River Systems, Inc. All Rights Reserved.
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#ifdef CONFIG_VT
+#include <linux/kgdb.h>
+#include <linux/console.h>
+#include <linux/vt_kern.h>
+#include <linux/selection.h>
+#include <linux/kdb.h>
+#include "kdb/kdb_private.h"
+
+static int dbg_orig_vc_mode;
+static int saved_fg_con;
+static int saved_last_con;
+static int saved_want_con;
+
+void dbg_pre_vt_hook(void)
+{
+ struct vc_data *vc = vc_cons[fg_console].d;
+ saved_fg_con = fg_console;
+ saved_last_con = last_console;
+ saved_want_con = want_console;
+ dbg_orig_vc_mode = vc->vc_mode;
+ vc->vc_mode = KD_TEXT;
+ console_blanked = 0;
+ vc->vc_sw->con_blank(vc, 0, 1);
+ vc->vc_sw->con_set_palette(vc, color_table);
+#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 */
+}
+EXPORT_SYMBOL_GPL(dbg_pre_vt_hook);
+
+void dbg_post_vt_hook(void)
+{
+ fg_console = saved_fg_con;
+ last_console = saved_last_con;
+ want_console = saved_want_con;
+ vc_cons[fg_console].d->vc_mode = dbg_orig_vc_mode;
+}
+EXPORT_SYMBOL_GPL(dbg_post_vt_hook);
+#endif /* CONFIG_VT */
--
1.6.3.1.9.g95405b

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/