Skip to content

[内核崩溃] msm_drm 显示驱动 HDCP commit 流程中 NULL 指针解引用导致 panic #19

@xueshiji

Description

@xueshiji

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_addrNULL(寄存器 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.kocomplete_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 硬件块:

  1. 未被成功分配/初始化(硬件块分配失败但未传播错误)
  2. 已在运行时被释放/反初始化(如显示管道状态转换、电源状态变化、DP 热插拔事件)
  3. 但 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 硬件块初始化状态的检查

崩溃触发场景推测

基于以上分析,最可能的崩溃场景:

  1. 显示管道发生状态转换(DP 热插拔、分辨率切换、电源状态变化等)
  2. HDCP 硬件块被释放或反初始化,blk_addr 被置为 NULL
  3. 但 connector 的软件状态仍标记 HDCP 为 active/enabled
  4. 一个 atomic commit 请求被提交
  5. complete_commit未验证 HDCP 硬件块是否仍然有效 的情况下,直接调用 drm_atomic_helper_commit_planes
  6. sde_crtc_atomic_beginsde_connector_hdcp_commit_setupdpu_reg_write(NULL + offset) → NULL 指针解引用 → 内核 panic

建议修复方向

  1. complete_commit 执行顺序调整:将 connector/HDCP 状态验证逻辑(当前位于 commit_planes 之后的 connector 循环中)移至 drm_atomic_helper_commit_planes 调用之前,确保所有相关硬件块已被验证为有效后再进入 commit 流程

  2. sde_crtc_atomic_begin 添加硬件块有效性检查:在进入 HDCP commit setup 路径前,检查 HDCP 硬件块的 dpu_hw_blk_reg_map.blk_addr 是否为非 NULL

  3. 状态同步:确保 HDCP 硬件块的释放/反初始化与 connector 软件状态的更新保持原子性,避免出现硬件已释放但软件状态仍标记 active 的不一致情况

复现信息

  • 复现概率:低(设备运行 25.7 小时后首次出现)
  • 可能触发条件:显示管道状态变化 + HDCP 硬件块反初始化 + 并发 atomic commit

attachment.zip

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions