drm/panic: Add a kmsg panic screen
Add a kmsg option, which will display the last lines of kmsg, and should be similar to fbcon. Add a drm.panic_screen module parameter, so you can choose between the different panic screens available. two options currently, but more will be added later: * "user": a short message telling the user to reboot the machine. * "kmsg": fill the screen with the last lines of kmsg. You can even change it at runtime by writing to /sys/module/drm/parameters/panic_screen v2: * Use module parameter instead of Kconfig choice (Javier Martinez Canillas) v3: * Add help for module parameter usage in Kconfig (Javier Martivez Canillas) * Fix use of font->height before checking it isn't null. (kernel test robot, Dan Carpenter) Signed-off-by: Jocelyn Falempe <jfalempe@redhat.com> Reviewed-by: Javier Martinez Canillas <javierm@redhat.com> Link: https://patchwork.freedesktop.org/patch/msgid/20240603095343.39588-4-jfalempe@redhat.com
This commit is contained in:
parent
24d07f114e
commit
54034bebb2
@ -137,6 +137,19 @@ config DRM_PANIC_DEBUG
|
||||
This is unsafe and should not be enabled on a production build.
|
||||
If in doubt, say "N".
|
||||
|
||||
config DRM_PANIC_SCREEN
|
||||
string "Panic screen formater"
|
||||
default "user"
|
||||
depends on DRM_PANIC
|
||||
help
|
||||
This option enable to choose what will be displayed when a kernel
|
||||
panic occurs. You can choose between "user", a short message telling
|
||||
the user to reboot the system, or "kmsg" which will display the last
|
||||
lines of kmsg.
|
||||
This can also be overridden by drm.panic_screen=xxxx kernel parameter
|
||||
or by writing to /sys/module/drm/parameters/panic_screen sysfs entry
|
||||
Default is "user"
|
||||
|
||||
config DRM_DEBUG_DP_MST_TOPOLOGY_REFS
|
||||
bool "Enable refcount backtrace history in the DP MST helpers"
|
||||
depends on STACKTRACE_SUPPORT
|
||||
|
@ -12,6 +12,7 @@
|
||||
#include <linux/kmsg_dump.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/printk.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
#include <drm/drm_drv.h>
|
||||
@ -27,6 +28,12 @@ MODULE_AUTHOR("Jocelyn Falempe");
|
||||
MODULE_DESCRIPTION("DRM panic handler");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
static char drm_panic_screen[16] = CONFIG_DRM_PANIC_SCREEN;
|
||||
module_param_string(panic_screen, drm_panic_screen, sizeof(drm_panic_screen), 0644);
|
||||
MODULE_PARM_DESC(panic_screen,
|
||||
"Choose what will be displayed by drm_panic, 'user' or 'kmsg' [default="
|
||||
CONFIG_DRM_PANIC_SCREEN "]");
|
||||
|
||||
/**
|
||||
* DOC: overview
|
||||
*
|
||||
@ -437,24 +444,18 @@ static void draw_txt_rectangle(struct drm_scanout_buffer *sb,
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Draw the panic message at the center of the screen
|
||||
*/
|
||||
static void draw_panic_static(struct drm_scanout_buffer *sb)
|
||||
static void draw_panic_static_user(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,
|
||||
@ -477,6 +478,85 @@ static void draw_panic_static(struct drm_scanout_buffer *sb)
|
||||
draw_txt_rectangle(sb, font, panic_msg, msg_lines, true, &r_msg, fg_color);
|
||||
}
|
||||
|
||||
/*
|
||||
* 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_kmsg(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;
|
||||
|
||||
if (!font)
|
||||
return;
|
||||
|
||||
yoffset = sb->height - font->height - (sb->height % font->height) / 2;
|
||||
|
||||
/* 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--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* drm_panic_is_format_supported()
|
||||
* @format: a fourcc color code
|
||||
@ -491,6 +571,15 @@ static bool drm_panic_is_format_supported(const struct drm_format_info *format)
|
||||
return convert_from_xrgb8888(0xffffff, format->format) != 0;
|
||||
}
|
||||
|
||||
static void draw_panic_dispatch(struct drm_scanout_buffer *sb)
|
||||
{
|
||||
if (!strcmp(drm_panic_screen, "kmsg")) {
|
||||
draw_panic_static_kmsg(sb);
|
||||
} else {
|
||||
draw_panic_static_user(sb);
|
||||
}
|
||||
}
|
||||
|
||||
static void draw_panic_plane(struct drm_plane *plane)
|
||||
{
|
||||
struct drm_scanout_buffer sb;
|
||||
@ -503,7 +592,7 @@ static void draw_panic_plane(struct drm_plane *plane)
|
||||
ret = plane->helper_private->get_scanout_buffer(plane, &sb);
|
||||
|
||||
if (!ret && drm_panic_is_format_supported(sb.format)) {
|
||||
draw_panic_static(&sb);
|
||||
draw_panic_dispatch(&sb);
|
||||
if (plane->helper_private->panic_flush)
|
||||
plane->helper_private->panic_flush(plane);
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user