[PATCH v3] drm/panic: allow overriding panic QR code URL
From: 纳西妲 · Nahida
Date: Fri Oct 02 2026 - 22:04:34 EST
The base URL used for the panic QR code is currently fixed at build time
by CONFIG_DRM_PANIC_SCREEN_QR_CODE_URL. Changing the panic report
endpoint therefore requires rebuilding the kernel.
Add a drm.panic_qr_url module parameter to allow overriding the URL at
boot or module load time, while keeping the Kconfig value as the
default.
Keep the parameter read-only after initialization so the panic path can
access it without additional synchronization.
Expose the configured URL to the DRM panic helper through an internal
getter so the helper can use the runtime value when generating the QR
code.
Assisted-by: LLM
Signed-off-by: 纳西妲 · Nahida <me@xxxxxxxxx>
---
v3:
- Add a compile-time check that limits the Kconfig default URL to 255
bytes, ensuring panic_qr_url is always NUL-terminated.
- Document the 255-byte URL limit.
v2: https://lore.kernel.org/r/20261002222021.149450-1-me@xxxxxxxxx
v1: https://lore.kernel.org/r/20261002203140.121165-1-me@xxxxxxxxx
Tested on x86_64:
- Full modular build with DRM=m and DRM_KMS_HELPER=m.
- QEMU/virtio-gpu runtime override with a non-empty Kconfig default URL.
- QEMU/virtio-gpu runtime fallback to the Kconfig default URL.
- QEMU/virtio-gpu runtime override with an empty Kconfig default URL.
- QEMU/virtio-gpu raw kmsg QR fallback with no configured URL.
- QEMU/virtio-gpu runtime override with a 255-byte base URL.
- Kconfig default URL length boundary: 255 bytes builds successfully,
while 256 bytes is rejected at compile time.
drivers/gpu/drm/Kconfig | 10 ++++++----
drivers/gpu/drm/drm_panic.c | 11 +++++++++++
drivers/gpu/drm/drm_panic_helper.c | 17 +++++++++++------
drivers/gpu/drm/drm_panic_internal.h | 4 ++++
4 files changed, 32 insertions(+), 10 deletions(-)
diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig
index 61111d50b..5216120c4 100644
--- a/drivers/gpu/drm/Kconfig
+++ b/drivers/gpu/drm/Kconfig
@@ -111,12 +111,14 @@ config DRM_PANIC_SCREEN_QR_CODE_URL
string "Base URL of the QR code in the panic screen"
depends on DRM_PANIC_SCREEN_QR_CODE
help
- This option sets the base URL to report the kernel panic. If it's set
- the QR code will contain the URL and the kmsg compressed with zlib as
- a URL parameter. If it's empty, the QR code will contain the kmsg as
- uncompressed text only.
+ This option sets the default base URL to report the kernel panic. If
+ it's set the QR code will contain the URL and the kmsg compressed with
+ zlib as a URL parameter. If it's empty, the QR code will contain the
+ kmsg as uncompressed text only. It can be overridden with the
+ drm.panic_qr_url=<url> kernel parameter.
There is a demo code in javascript, to decode and uncompress the kmsg
data from the URL parameter at https://github.com/kdj0c/panic_report
+ The URL must not exceed 255 bytes.
config DRM_PANIC_SCREEN_QR_VERSION
int "Maximum version (size) of the QR code."
diff --git a/drivers/gpu/drm/drm_panic.c b/drivers/gpu/drm/drm_panic.c
index 9fe97c4ed..9cc8c2f95 100644
--- a/drivers/gpu/drm/drm_panic.c
+++ b/drivers/gpu/drm/drm_panic.c
@@ -49,6 +49,17 @@ MODULE_LICENSE("GPL");
static uint panic_qr_version = CONFIG_DRM_PANIC_SCREEN_QR_VERSION;
module_param(panic_qr_version, uint, 0644);
MODULE_PARM_DESC(panic_qr_version, "maximum version (size) of the QR code");
+static char panic_qr_url[256] = CONFIG_DRM_PANIC_SCREEN_QR_CODE_URL;
+static_assert(sizeof(CONFIG_DRM_PANIC_SCREEN_QR_CODE_URL) <= sizeof(panic_qr_url),
+ "CONFIG_DRM_PANIC_SCREEN_QR_CODE_URL must be at most 255 bytes");
+module_param_string(panic_qr_url, panic_qr_url, sizeof(panic_qr_url), 0444);
+MODULE_PARM_DESC(panic_qr_url, "base URL of the QR code in the panic screen");
+
+const char *drm_panic_get_qr_url(void)
+{
+ return panic_qr_url;
+}
+EXPORT_SYMBOL_GPL(drm_panic_get_qr_url);
#endif
static enum drm_panic_type drm_panic_type = -1;
diff --git a/drivers/gpu/drm/drm_panic_helper.c b/drivers/gpu/drm/drm_panic_helper.c
index 8913c3d22..b0ea0b4e8 100644
--- a/drivers/gpu/drm/drm_panic_helper.c
+++ b/drivers/gpu/drm/drm_panic_helper.c
@@ -609,17 +609,20 @@ static void drm_panic_helper_qr_exit(void)
stream.workspace = NULL;
}
-static int drm_panic_helper_get_qr_code_url(u8 **qr_image, unsigned int qr_version)
+static int drm_panic_helper_get_qr_code_url(u8 **qr_image, unsigned int qr_version,
+ const char *qr_url)
{
struct kmsg_dump_iter iter;
- char url[256];
+ char url[512];
size_t kmsg_len, max_kmsg_size;
char *kmsg;
int max_qr_data_size, url_len;
url_len = snprintf(url, sizeof(url), "%s?a=%s&v=%s&z=",
- CONFIG_DRM_PANIC_SCREEN_QR_CODE_URL,
- utsname()->machine, utsname()->release);
+ qr_url, utsname()->machine, utsname()->release);
+
+ if (url_len >= (int)sizeof(url))
+ return -E2BIG;
max_qr_data_size = drm_panic_helper_qr_max_data_size(qr_version, url_len);
max_kmsg_size = min(MAX_ZLIB_RATIO * max_qr_data_size, QR_BUFFER1_SIZE);
@@ -686,8 +689,10 @@ static int drm_panic_helper_get_qr_code_raw(u8 **qr_image, unsigned int qr_versi
static int drm_panic_helper_get_qr_code(u8 **qr_image, unsigned int qr_version)
{
- if (strlen(CONFIG_DRM_PANIC_SCREEN_QR_CODE_URL) > 0)
- return drm_panic_helper_get_qr_code_url(qr_image, qr_version);
+ const char *qr_url = drm_panic_get_qr_url();
+
+ if (qr_url[0])
+ return drm_panic_helper_get_qr_code_url(qr_image, qr_version, qr_url);
else
return drm_panic_helper_get_qr_code_raw(qr_image, qr_version);
}
diff --git a/drivers/gpu/drm/drm_panic_internal.h b/drivers/gpu/drm/drm_panic_internal.h
index fe6d514a0..f33552265 100644
--- a/drivers/gpu/drm/drm_panic_internal.h
+++ b/drivers/gpu/drm/drm_panic_internal.h
@@ -14,6 +14,10 @@ struct drm_device;
#ifdef CONFIG_DRM_PANIC
+#if IS_ENABLED(CONFIG_DRM_PANIC_SCREEN_QR_CODE)
+const char *drm_panic_get_qr_url(void);
+#endif
+
/**
* drm_panic_lock - protect panic printing relevant state
* @dev: struct drm_device
base-commit: 54e61ea6c492d69a1717018826d8340810c812eb
--
2.55.0