OnePlus PJZ110 内核崩溃报告 — msm_drm 显示驱动 NULL 指针崩溃
设备信息
| 项目 |
值 |
| 设备型号 |
OnePlus PJZ110 |
| 硬件平台 |
OP5D0DL1 (SM8750) |
| Android 版本 |
16 (BP2A.250605.015) |
| 内核版本 |
6.6.89-android15-8-g7e1f3c083cc6 |
| 构建指纹 |
OnePlus/PJZ110/OP5D0DL1:16/BP2A.250605.015/V.3890a4c-14ef1e9-14f2de5:user/release-keys |
| SELinux |
Enforcing |
| 运行时长 |
~25.7 小时(92574 秒) |
崩溃摘要
设备在正常运行约 25.7 小时后发生内核 panic:
msm_drm 显示驱动在 HDCP(High-bandwidth Digital Content Protection)提交流程中访问了 NULL 指针,导致 writel_relaxed() 写入地址 0x00000000 + offset。崩溃前 kgsl GPU 驱动报告了 "device is power off",表明显示管道正在经历状态转换。
CPU1 崩溃调用栈(msm_drm — 根因)
Call trace:
writel_relaxed+0x2c/0x9c [msm_drm]
dpu_reg_write+0x74/0x?? [msm_drm]
[中间函数]+0x??/0xB8 [msm_drm]
sde_connector_hdcp_commit_setup+0x120/0x1a4 [msm_drm]
sde_crtc_atomic_begin+0x??4/0x??4 [msm_drm]
drm_atomic_helper_commit_planes+0x??/0x??1
complete_commit+0x??/0xa0 [msm_drm]
_msm_drm_commit_work_cb+0x04/0x144 [msm_drm]
kthread_delayed_work_fn+0x11c/0x224
kthread+0x114/0x1c
ret_from_fork+0x10/0x20
技术分析
崩溃机制
dpu_reg_write() 尝试向 dpu_hw_blk_reg_map->blk_addr + reg_off 写入寄存器值,但 blk_addr 为 NULL(寄存器 x19 = 0x0000000000000000),导致写入地址 0x00000000 + offset,触发内核 panic。
// drivers/gpu/drm/msm/disp/dpu1/dpu_hw_util.c:99
void dpu_reg_write(struct dpu_hw_blk_reg_map *c, u32 reg_off, u32 val, const char *name)
{
writel_relaxed(val, c->blk_addr + reg_off); // blk_addr == NULL → crash
}
根因:vendor complete_commit 函数执行顺序缺陷
通过对 msm_drm.ko 中 complete_commit 函数的重定位表分析,确认其内部执行顺序如下:
| 步骤 |
偏移 |
调用函数 |
说明 |
| ① |
0x1cdce0 |
drm_atomic_helper_wait_for_fences |
等待 fence |
| ② |
0x1cdd10 |
[vtable+0x38] prepare_commit |
KMS 准备 |
| ③ |
0x1cdd1c |
msm_atomic_helper_commit_modeset_disables |
modeset 禁用 |
| ④ |
0x1cdd2c |
drm_atomic_helper_commit_planes |
触发崩溃 |
| ⑤ |
0x1cdd48 |
connector 循环 1 — HDCP 状态验证 |
验证在崩溃之后 |
| ⑥ |
0x1cdfc0 |
connector 循环 2 — DP stream 验证 |
验证在崩溃之后 |
| ⑦ |
0x1ce164 |
connector 循环 3 — bridge 操作 |
验证在崩溃之后 |
| ⑧ |
0x1ce024 |
drm_atomic_bridge_chain_pre_enable |
bridge 预启用 |
| ⑨ |
0x1ce21c |
drm_atomic_bridge_chain_enable |
bridge 启用 |
| ⑩ |
0x1ce444 |
[vtable+0x48] complete_commit |
KMS 完成 |
| ⑪ |
0x1ce418 |
drm_atomic_helper_cleanup_planes |
清理 |
关键问题:步骤 ④ 调用 drm_atomic_helper_commit_planes,该函数遍历所有 CRTC 并调用 sde_crtc_atomic_begin,后者在 vendor 实现中进入 HDCP 提交设置路径。然而,对 connector/HDCP 硬件块状态的验证逻辑位于步骤 ⑤~⑦ 的 connector 循环中,即验证发生在崩溃点之后。
blk_addr 为 NULL 的原因
dpu_hw_blk_reg_map.blk_addr 在 DPU 驱动初始化期间由 dpu_rm_init() 通过 dpu_kms->mmio + catalog_offset 赋值。该值为 NULL 表明对应的 HDCP 硬件块:
- 未被成功分配/初始化(硬件块分配失败但未传播错误)
- 已在运行时被释放/反初始化(如显示管道状态转换、电源状态变化、DP 热插拔事件)
- 但 connector 状态仍标记 HDCP 为 active,导致 commit 流程仍尝试访问该硬件块
对比上游开源代码
上游开源 msm_atomic_commit_tail()(drivers/gpu/drm/msm/msm_atomic.c:202)的流程为:
kms->funcs->prepare_commit(kms, state);
drm_atomic_helper_commit_modeset_disables(dev, state);
drm_atomic_helper_commit_planes(dev, state, 0); // 开源的 atomic_begin 不含 HDCP
drm_atomic_helper_commit_modeset_enables(dev, state);
kms->funcs->flush_commit(kms, crtc_mask);
kms->funcs->complete_commit(kms, crtc_mask);
上游开源的 dpu_crtc_atomic_begin()(drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c:809)仅包含 blend setup、mixer 边界设置、颜色管理等功能,不包含任何 HDCP 路径。HDCP commit setup 是 vendor 版本 sde_crtc_atomic_begin 中额外添加的,但缺少对 HDCP 硬件块初始化状态的检查。
崩溃触发场景推测
基于以上分析,最可能的崩溃场景:
- 显示管道发生状态转换(DP 热插拔、分辨率切换、电源状态变化等)
- HDCP 硬件块被释放或反初始化,
blk_addr 被置为 NULL
- 但 connector 的软件状态仍标记 HDCP 为 active/enabled
- 一个 atomic commit 请求被提交
complete_commit 在 未验证 HDCP 硬件块是否仍然有效 的情况下,直接调用 drm_atomic_helper_commit_planes
sde_crtc_atomic_begin → sde_connector_hdcp_commit_setup → dpu_reg_write(NULL + offset) → NULL 指针解引用 → 内核 panic
建议修复方向
-
complete_commit 执行顺序调整:将 connector/HDCP 状态验证逻辑(当前位于 commit_planes 之后的 connector 循环中)移至 drm_atomic_helper_commit_planes 调用之前,确保所有相关硬件块已被验证为有效后再进入 commit 流程
-
sde_crtc_atomic_begin 添加硬件块有效性检查:在进入 HDCP commit setup 路径前,检查 HDCP 硬件块的 dpu_hw_blk_reg_map.blk_addr 是否为非 NULL
-
状态同步:确保 HDCP 硬件块的释放/反初始化与 connector 软件状态的更新保持原子性,避免出现硬件已释放但软件状态仍标记 active 的不一致情况
复现信息
- 复现概率:低(设备运行 25.7 小时后首次出现)
- 可能触发条件:显示管道状态变化 + HDCP 硬件块反初始化 + 并发 atomic commit
attachment.zip
OnePlus PJZ110 内核崩溃报告 — msm_drm 显示驱动 NULL 指针崩溃
设备信息
崩溃摘要
设备在正常运行约 25.7 小时后发生内核 panic:
msm_drm显示驱动在 HDCP(High-bandwidth Digital Content Protection)提交流程中访问了 NULL 指针,导致writel_relaxed()写入地址0x00000000 + offset。崩溃前 kgsl GPU 驱动报告了 "device is power off",表明显示管道正在经历状态转换。CPU1 崩溃调用栈(msm_drm — 根因)
技术分析
崩溃机制
dpu_reg_write()尝试向dpu_hw_blk_reg_map->blk_addr + reg_off写入寄存器值,但blk_addr为NULL(寄存器 x19 =0x0000000000000000),导致写入地址0x00000000 + offset,触发内核 panic。根因:vendor
complete_commit函数执行顺序缺陷通过对
msm_drm.ko中complete_commit函数的重定位表分析,确认其内部执行顺序如下:drm_atomic_helper_wait_for_fences[vtable+0x38]prepare_commitmsm_atomic_helper_commit_modeset_disablesdrm_atomic_helper_commit_planesdrm_atomic_bridge_chain_pre_enabledrm_atomic_bridge_chain_enable[vtable+0x48]complete_commitdrm_atomic_helper_cleanup_planes关键问题:步骤 ④ 调用
drm_atomic_helper_commit_planes,该函数遍历所有 CRTC 并调用sde_crtc_atomic_begin,后者在 vendor 实现中进入 HDCP 提交设置路径。然而,对 connector/HDCP 硬件块状态的验证逻辑位于步骤 ⑤~⑦ 的 connector 循环中,即验证发生在崩溃点之后。blk_addr为 NULL 的原因dpu_hw_blk_reg_map.blk_addr在 DPU 驱动初始化期间由dpu_rm_init()通过dpu_kms->mmio + catalog_offset赋值。该值为 NULL 表明对应的 HDCP 硬件块:对比上游开源代码
上游开源
msm_atomic_commit_tail()(drivers/gpu/drm/msm/msm_atomic.c:202)的流程为:上游开源的
dpu_crtc_atomic_begin()(drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c:809)仅包含 blend setup、mixer 边界设置、颜色管理等功能,不包含任何 HDCP 路径。HDCP commit setup 是 vendor 版本sde_crtc_atomic_begin中额外添加的,但缺少对 HDCP 硬件块初始化状态的检查。崩溃触发场景推测
基于以上分析,最可能的崩溃场景:
blk_addr被置为 NULLcomplete_commit在 未验证 HDCP 硬件块是否仍然有效 的情况下,直接调用drm_atomic_helper_commit_planessde_crtc_atomic_begin→sde_connector_hdcp_commit_setup→dpu_reg_write(NULL + offset)→ NULL 指针解引用 → 内核 panic建议修复方向
complete_commit执行顺序调整:将 connector/HDCP 状态验证逻辑(当前位于commit_planes之后的 connector 循环中)移至drm_atomic_helper_commit_planes调用之前,确保所有相关硬件块已被验证为有效后再进入 commit 流程sde_crtc_atomic_begin添加硬件块有效性检查:在进入 HDCP commit setup 路径前,检查 HDCP 硬件块的dpu_hw_blk_reg_map.blk_addr是否为非 NULL状态同步:确保 HDCP 硬件块的释放/反初始化与 connector 软件状态的更新保持原子性,避免出现硬件已释放但软件状态仍标记 active 的不一致情况
复现信息
attachment.zip