Skip to content

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

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

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions