[PATCH 3/3] drm/panic: Add a kmsg dump screen
Jocelyn Falempe
jfalempe at redhat.com
Fri May 31 08:06:34 UTC 2024
Add a kmsg dump option, which will display the last lines of kmsg,
and should be similar to fbcon.
Add a Kconfig choice for the panic screen, so that the user can
choose between this new kmsg dump, or the userfriendly option.
Signed-off-by: Jocelyn Falempe <jfalempe at redhat.com>
---
drivers/gpu/drm/Kconfig | 21 +++++
drivers/gpu/drm/drm_panic.c | 151 +++++++++++++++++++++++++++---------
2 files changed, 136 insertions(+), 36 deletions(-)
diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig
index 9703429de6b9..78d401b55102 100644
--- a/drivers/gpu/drm/Kconfig
+++ b/drivers/gpu/drm/Kconfig
@@ -137,6 +137,27 @@ config DRM_PANIC_DEBUG
This is unsafe and should not be enabled on a production build.
If in doubt, say "N".
+choice
+ prompt "Panic screen formater"
+ default DRM_PANIC_SCREEN_USERFRIENDLY
+ depends on DRM_PANIC
+ help
+ This option enable to choose what will be displayed when a kernel
+ panic occurs.
+
+ config DRM_PANIC_SCREEN_USERFRIENDLY
+ bool "Default user friendly message"
+ help
+ Only a short message telling the user to reboot the system.
+
+ config DRM_PANIC_SCREEN_KMSG
+ bool "Display the last lines of kmsg"
+ help
+ Display kmsg last lines on panic.
+ Enable if you are a kernel developer, and want to debug a
+ kernel panic.
+endchoice
+
config DRM_DEBUG_DP_MST_TOPOLOGY_REFS
bool "Enable refcount backtrace history in the DP MST helpers"
depends on STACKTRACE_SUPPORT
diff --git a/drivers/gpu/drm/drm_panic.c b/drivers/gpu/drm/drm_panic.c
index 27e26b9d842c..71f6f566d64b 100644
--- a/drivers/gpu/drm/drm_panic.c
+++ b/drivers/gpu/drm/drm_panic.c
@@ -63,24 +63,6 @@ struct drm_panic_line {
const char *txt;
};
-#define PANIC_LINE(s) {.len = sizeof(s) - 1, .txt = s}
-
-static struct drm_panic_line panic_msg[] = {
- PANIC_LINE("KERNEL PANIC !"),
- PANIC_LINE(""),
- PANIC_LINE("Please reboot your computer."),
-};
-
-static const struct drm_panic_line logo[] = {
- PANIC_LINE(" .--. _"),
- PANIC_LINE(" |o_o | | |"),
- PANIC_LINE(" |:_/ | | |"),
- PANIC_LINE(" // \\ \\ |_|"),
- PANIC_LINE(" (| | ) _"),
- PANIC_LINE(" /'\\_ _/`\\ (_)"),
- PANIC_LINE(" \\___)=(___/"),
-};
-
/*
* Color conversion
*/
@@ -385,16 +367,6 @@ static const u8 *get_char_bitmap(const struct font_desc *font, char c, size_t fo
return font->data + (c * font->height) * font_pitch;
}
-static unsigned int get_max_line_len(const struct drm_panic_line *lines, int len)
-{
- int i;
- unsigned int max = 0;
-
- for (i = 0; i < len; i++)
- max = max(lines[i].len, max);
- return max;
-}
-
/*
* Draw a text in a rectangle on a framebuffer. The text is truncated if it overflows the rectangle
*/
@@ -431,24 +403,48 @@ static void draw_txt_rectangle(struct drm_scanout_buffer *sb,
}
}
-/*
- * Draw the panic message at the center of the screen
- */
+#if defined(CONFIG_DRM_PANIC_SCREEN_USERFRIENDLY)
+
+#define PANIC_LINE(s) {.len = sizeof(s) - 1, .txt = s}
+
+static struct drm_panic_line panic_msg[] = {
+ PANIC_LINE("KERNEL PANIC !"),
+ PANIC_LINE(""),
+ PANIC_LINE("Please reboot your computer."),
+};
+
+static const struct drm_panic_line logo[] = {
+ PANIC_LINE(" .--. _"),
+ PANIC_LINE(" |o_o | | |"),
+ PANIC_LINE(" |:_/ | | |"),
+ PANIC_LINE(" // \\ \\ |_|"),
+ PANIC_LINE(" (| | ) _"),
+ PANIC_LINE(" /'\\_ _/`\\ (_)"),
+ PANIC_LINE(" \\___)=(___/"),
+};
+
+static unsigned int get_max_line_len(const struct drm_panic_line *lines, int len)
+{
+ int i;
+ unsigned int max = 0;
+
+ for (i = 0; i < len; i++)
+ max = max(lines[i].len, max);
+ return max;
+}
+
static void draw_panic_static(struct drm_scanout_buffer *sb)
{
size_t msg_lines = ARRAY_SIZE(panic_msg);
size_t logo_lines = ARRAY_SIZE(logo);
- u32 fg_color = CONFIG_DRM_PANIC_FOREGROUND_COLOR;
- u32 bg_color = CONFIG_DRM_PANIC_BACKGROUND_COLOR;
+ u32 fg_color = convert_from_xrgb8888(CONFIG_DRM_PANIC_FOREGROUND_COLOR, sb->format->format);
+ u32 bg_color = convert_from_xrgb8888(CONFIG_DRM_PANIC_BACKGROUND_COLOR, sb->format->format);
const struct font_desc *font = get_default_font(sb->width, sb->height, NULL, NULL);
struct drm_rect r_screen, r_logo, r_msg;
if (!font)
return;
- fg_color = convert_from_xrgb8888(fg_color, sb->format->format);
- bg_color = convert_from_xrgb8888(bg_color, sb->format->format);
-
r_screen = DRM_RECT_INIT(0, 0, sb->width, sb->height);
r_logo = DRM_RECT_INIT(0, 0,
@@ -471,6 +467,89 @@ static void draw_panic_static(struct drm_scanout_buffer *sb)
draw_txt_rectangle(sb, font, panic_msg, msg_lines, true, &r_msg, fg_color);
}
+#elif defined(CONFIG_DRM_PANIC_SCREEN_KMSG)
+
+#include <linux/kmsg_dump.h>
+#include <linux/printk.h>
+
+/*
+ * Draw one line of kmsg, and handle wrapping if it won't fit in the screen width.
+ * Return the y-offset of the next line.
+ */
+static int draw_line_with_wrap(struct drm_scanout_buffer *sb, const struct font_desc *font,
+ struct drm_panic_line *line, int yoffset, u32 fg_color)
+{
+ int chars_per_row = sb->width / font->width;
+ struct drm_rect r_txt = DRM_RECT_INIT(0, yoffset, sb->width, sb->height);
+ struct drm_panic_line line_wrap;
+
+ if (line->len > chars_per_row) {
+ line_wrap.len = line->len % chars_per_row;
+ line_wrap.txt = line->txt + line->len - line_wrap.len;
+ draw_txt_rectangle(sb, font, &line_wrap, 1, false, &r_txt, fg_color);
+ r_txt.y1 -= font->height;
+ if (r_txt.y1 < 0)
+ return r_txt.y1;
+ while (line_wrap.txt > line->txt) {
+ line_wrap.txt -= chars_per_row;
+ line_wrap.len = chars_per_row;
+ draw_txt_rectangle(sb, font, &line_wrap, 1, false, &r_txt, fg_color);
+ r_txt.y1 -= font->height;
+ if (r_txt.y1 < 0)
+ return r_txt.y1;
+ }
+ } else {
+ draw_txt_rectangle(sb, font, line, 1, false, &r_txt, fg_color);
+ r_txt.y1 -= font->height;
+ }
+ return r_txt.y1;
+}
+
+/*
+ * Draw the kmsg buffer to the screen, starting from the youngest message at the bottom,
+ * and going up until reaching the top of the screen.
+ */
+static void draw_panic_static(struct drm_scanout_buffer *sb)
+{
+ u32 fg_color = convert_from_xrgb8888(CONFIG_DRM_PANIC_FOREGROUND_COLOR, sb->format->format);
+ u32 bg_color = convert_from_xrgb8888(CONFIG_DRM_PANIC_BACKGROUND_COLOR, sb->format->format);
+ const struct font_desc *font = get_default_font(sb->width, sb->height, NULL, NULL);
+ struct drm_rect r_screen = DRM_RECT_INIT(0, 0, sb->width, sb->height);
+ struct kmsg_dump_iter iter;
+ char kmsg_buf[512];
+ size_t kmsg_len;
+ struct drm_panic_line line;
+ int yoffset = sb->height - font->height - (sb->height % font->height) / 2;
+
+ if (!font)
+ return;
+
+ /* Fill with the background color, and draw text on top */
+ drm_panic_fill(sb, &r_screen, bg_color);
+
+ kmsg_dump_rewind(&iter);
+ while (kmsg_dump_get_buffer(&iter, false, kmsg_buf, sizeof(kmsg_buf), &kmsg_len)) {
+ char *start;
+ char *end;
+
+ /* ignore terminating NUL and newline */
+ start = kmsg_buf + kmsg_len - 2;
+ end = kmsg_buf + kmsg_len - 1;
+ while (start > kmsg_buf && yoffset >= 0) {
+ while (start > kmsg_buf && *start != '\n')
+ start--;
+ /* don't count the newline character */
+ line.txt = start + (start == kmsg_buf ? 0 : 1);
+ line.len = end - line.txt;
+
+ yoffset = draw_line_with_wrap(sb, font, &line, yoffset, fg_color);
+ end = start;
+ start--;
+ }
+ }
+}
+#endif
+
/*
* drm_panic_is_format_supported()
* @format: a fourcc color code
--
2.45.1
More information about the dri-devel
mailing list