Skip to content

feat(drm): per-buffer dumb allocation with GEM-refcounted mmap pages#514

Merged
ZR233 merged 2 commits into
rcore-os:devfrom
JosephJoshua:drm-perbuf
May 31, 2026
Merged

feat(drm): per-buffer dumb allocation with GEM-refcounted mmap pages#514
ZR233 merged 2 commits into
rcore-os:devfrom
JosephJoshua:drm-perbuf

Conversation

@JosephJoshua

@JosephJoshua JosephJoshua commented May 10, 2026

Copy link
Copy Markdown
Contributor

Problem

F+G+H+I 留下的 DUMB 模型是 "所有 dumb buffer 都指向同一段 axdisplay scanout"。两个 DUMB 写出来会互相覆盖,weston pixman 的双缓冲翻页跑不起来。同时 DESTROY_DUMB 一旦释放底层物理页,已经 mmap 到用户空间的 PTE 就指向被回收的内存,使用-after-free 待发。

Changes

Per-buffer 物理内存 + 初始化清零

  • 每次 CREATE_DUMBGlobalPage::alloc_contiguous 单独拿一段页对齐的物理内存 (上限 8 MiB)。
  • GlobalPage::zero() 之后再交付,避免把内核残留页内容直接 mmap 给 userspace。
  • 不预留全局 heap,避免非图形启动多吃 128 MiB。

GEM-style 引用计数

  • DumbBuffer.pagesArc<GlobalPage> 持有。Card0 的 handle 表是其中一个强引用;DESTROY_DUMB 只是丢掉这个强引用,物理页是否真正释放取决于是否还有用户映射在引用。
  • DeviceMmap::Physical(PhysAddrRange, Option<Arc<dyn Any + Send + Sync>>) 多带一个 retainer 槽。Card0::mmapArc<GlobalPage> 克隆出来填进去。
  • LinearBackend 接住 retainer:每条 VMA 自己持一份强引用,被 munmap 或 aspace 整体丢弃时引用计数才会真正落到零。这条链路对齐 Linux DRM GEM 的 refcount 语义。
  • 其余 DeviceMmap::Physical 调用点 (fb.rs / card1.rs) 对应 long-lived 驱动 buffer,retainer 填 None,行为不变。

mmap offset key + 提交链路

  • MAP_DUMB 返回单调递增的 offset key 作为 mmap 查询入口。
  • mmap(offset)dumbs 里反查到对应 buffer 把 PhysAddrRange 加 retainer 一起返回。
  • SETCRTC / PAGE_FLIP / atomicTEST_ONLY commit 都走 present_fb(fb_id):按 fb_id 找到对应 dumb handle 和 pages,memcpy 到 axdisplay scanout,再 framebuffer_flush 推给 virtio-gpu。

Tests

新增 test_drm_perbuf_dumb (4 架构 toml) 覆盖完整路径:

  • CREATE_DUMB×2 拿不同 handle
  • MAP_DUMB×2 拿不同 offset
  • 两个 mmap 区域物理隔离 (写 buf2 不影响 buf1)
  • ADDFB2×2 拿不同 fb_id
  • 两次 atomic commit 在 fb1 / fb2 之间翻页

Dependencies

依赖 F+G+H+I 的 DRM 基线 (feat(drm): /dev/dri/card0 with legacy SETCRTC and atomic KMS)。本 PR 在 F+G+H+I 合入后 rebase 到 dev 即可编译。

Notes

PRIME (HANDLE_TO_FD / FD_TO_HANDLE)、hardware cursor plane、virtio-gpu 零拷贝资源 (resource_create_2d / set_scanout / transfer_to_host) 走后续 PR。

Sync with dev

  • 已将分支同步到最新 dev,并处理 card0.rsdevice.rsmmap.rs 的冲突。
  • 保留 dev 现有的 DeviceMmap::NotConfigured/SharedPages、kcov/SG2002/Ion mmap 和 DRM ioctl 支持,同时保留本 PR 的 per-buffer Arc<GlobalPage> 生命周期语义。
  • DeviceMmap::Physical 增加可选 retainer;sys_mmap 在存在 retainer 时使用 anchored linear backend,让 mmap 后的 dumb buffer 页在 DESTROY_DUMB 后仍由 VMA 持有。
  • 本地已执行 cargo fmt --checkcargo xtask clippy --package starry-kernel

@ZR233 ZR233 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

本地 fmt 和新 DRM 用例发现/执行基本可跑,但 starry-kernel clippy 当前失败;同时 dumb buffer 的 backing 生命周期和初始清零还会影响 DRM/GEM 语义与用户态内存安全,需要修正后再合入。

Comment thread os/StarryOS/kernel/src/pseudofs/dev/card0.rs
Comment thread os/StarryOS/kernel/src/pseudofs/dev/card0.rs
Comment thread os/StarryOS/kernel/src/pseudofs/dev/drm.rs Outdated
@JosephJoshua
JosephJoshua force-pushed the drm-perbuf branch 3 times, most recently from 72335e1 to 657a0d5 Compare May 12, 2026 14:39
@JosephJoshua JosephJoshua changed the title feat(drm): per-buffer dumb allocation with mmap offset key feat(drm): per-buffer dumb allocation with GEM-refcounted mmap pages May 12, 2026

@ZR233 ZR233 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

请求修改。

本地 cargo fmt --checkcargo xtask clippy --package starry-kernel 通过,cargo xtask starry test qemu --arch x86_64 -c test-drm-perbuf-dumb 也通过了,说明 per-buffer dumb allocation 主路径和新增用例已经接上了 runner。

但当前还有两个阻塞的 DRM 语义问题:

  1. ADDFB2 只记录了 fb_id -> handle,没有让 framebuffer 自己持有 dumb backing 的强引用。用户在 ADDFB2 之后执行 DESTROY_DUMBself.dumbs.remove() 会把 backing 从对象表移除,后续 PAGE_FLIP / atomic commit 再走 present_fb 时就找不到 buffer。这和 Linux DRM/GEM 的引用计数语义不一致。
  2. IN_FORMATS 是驱动内部生成的不可变属性 blob,但当前复用了用户 blob 表,并且 DESTROYPROPBLOB 可以把它删掉;in_formats_blob 缓存还不会同步清零,后续属性查询会继续返回一个已经失效的 blob id。

建议先修正这两处生命周期语义,并补对应回归测试后再合入。

Comment thread os/StarryOS/kernel/src/pseudofs/dev/card0.rs Outdated
Comment thread os/StarryOS/kernel/src/pseudofs/dev/card0.rs

@ZR233 ZR233 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

本轮复查了 per-buffer dumb allocation、DeviceMmap::Physical retainer、LinearBackend 引用保持、MAP_DUMB offset key、atomic/page-flip 提交路径,以及新增 Starry QEMU DRM 用例。mmap VMA 通过 retainer 持有 Arc 这一部分方向是对的,CREATE_DUMB 也已经清零 backing。

当前仍有三个阻塞问题:framebuffer 生命周期仍没有按 GEM 语义建模,fb 只保存 handle 而不持有 backing,DESTROY_DUMB 后 fb 仍存在但无法再 present;IN_FORMATS 内置 blob 仍可被用户删除,缓存 id 会变成悬空;此外新增 mod rtc 后没有注册 Rtc,导致 starry-kernel 全部 8 个 clippy feature 检查失败。

已验证:cargo fmt --check 通过;cargo xtask starry test qemu --arch x86_64 -c test-drm-perbuf-dumb 通过,输出 DONE: 26 pass, 0 fail。失败项:cargo xtask clippy --package starry-kernel,8 个检查均因 RTC0_DEVICE_ID never used 和 Rtc never constructed 失败。当前测试覆盖了双 dumb buffer、不同 mmap offset、两个 fb_id 和 fb1/fb2 atomic 翻页,但还没有覆盖 ADDFB2 后 DESTROY_DUMB 再提交,也没有覆盖删除 IN_FORMATS blob 后再次查询属性。

Comment thread os/StarryOS/kernel/src/pseudofs/dev/card0.rs Outdated
Comment thread os/StarryOS/kernel/src/pseudofs/dev/card0.rs
Comment thread os/StarryOS/kernel/src/pseudofs/dev/mod.rs
@JosephJoshua
JosephJoshua force-pushed the drm-perbuf branch 2 times, most recently from 48d9682 to dbfcd14 Compare May 13, 2026 09:34

@ZR233 ZR233 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

这版已经把 dumb mmap 的 VMA retainer、初始清零、per-buffer 分配和 x86_64 QEMU 覆盖补上了,starry-kernel clippy 也通过。PR 仍是 draft。

本地验证:cargo fmt --check 通过,cargo xtask clippy --package starry-kernel 通过,cargo xtask starry test qemu --arch x86_64 -c test-drm-perbuf-dumb --list 能发现用例,实际运行 test-drm-perbuf-dumb 通过。远端检查快照里仍有 clippy/sync-lint/Starry QEMU container jobs pending。

目前还有两个阻塞的 DRM/GEM 生命周期问题:framebuffer 没有持有 backing,DESTROY_DUMB 后 fb commit 会静默失效;内部 IN_FORMATS blob 仍可被用户删除并破坏后续属性查询。建议修复这两处所有权问题并补 destroy 后继续使用的回归测试。

Comment thread os/StarryOS/kernel/src/pseudofs/dev/card0.rs
Comment thread os/StarryOS/kernel/src/pseudofs/dev/card0.rs

@ZR233 ZR233 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

本轮复查的是新 head dbfcd14624ff0bcae4e27674e88cd3e84f67fdc6。之前两个 DRM/GEM 生命周期阻塞点已经从实现上修复:framebuffer 现在持有 Arc<GlobalPage>DESTROY_DUMB 不再让已创建 fb 的 backing 失效;IN_FORMATS 也已拆到 system_blobs 并禁止用户 DESTROYPROPBLOB 删除。x86_64 的 test-drm-perbuf-dumb 本地通过。

但当前 starry-kernel clippy 8 个配置全部失败,仍不满足项目的 crate 修改后 clippy 通过要求,需要修正后再合入。验证结果:cargo fmt --check 通过,cargo xtask starry test qemu --arch x86_64 -c test-drm-perbuf-dumb --list 能发现用例,实际运行 test-drm-perbuf-dumb 通过;cargo xtask clippy --package starry-kernel 失败,8/8 检查都卡在 os/StarryOS/kernel/src/pseudofs/dev/card0.rs:550manual_is_multiple_of

Comment thread os/StarryOS/kernel/src/pseudofs/dev/card0.rs Outdated

@ZR233 ZR233 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

per-buffer dumb 的本地 DRM case 能跑通,但 DRM blob/GEM 生命周期语义仍有阻塞问题,部分新增测试还把错误行为写成了期望。

验证通过:cargo fmt --checkcargo xtask clippy --package starry-kerneltest-drm-perbuf-dumb --listtest-drm-atomic --list,以及 x86_64 test-drm-perbuf-dumb。远端 gh pr checks 仍有 loongarch64 normal qemu busybox 失败,且多个 Starry container jobs 被取消。

Comment thread os/StarryOS/kernel/src/pseudofs/dev/card0.rs
Comment thread test-suit/starryos/normal/qemu-smp1/test-drm-atomic/c/src/main.c Outdated

@ZR233 ZR233 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

这版把上轮指出的 MODE_ID blob pinning 和 GEM destroy 后用例方向补上了,IN_FORMATS / framebuffer backing 的生命周期实现也比前几版完整;但当前 head 仍有两个阻塞问题,需要修改后再合入。

主要问题:

  1. 新增的 test-drm-perbuf-dumb 当前编译失败,远端 x86_64 Starry QEMU 失败也包含这个 case;本地单跑 cargo xtask starry test qemu --arch x86_64 -c test-drm-perbuf-dumb 复现为 uint8_t 写入/比较 32-bit magic 常量触发 -Werror
  2. legacy SETCRTC/GETCRTC 路径没有维护 CRTC/fb/connector state,也不校验 fb/connector 数组,导致无效 fb/connector 可以成功,且 drmModeSetCrtc()drmModeGetCrtc() 读不回绑定状态。

已验证:git diff --check origin/dev...HEAD 通过;git merge-tree --write-tree origin/dev HEAD 通过;cargo fmt --check 通过;cargo xtask clippy --package starry-kernel 8/8 通过。失败项:cargo xtask starry test qemu --arch x86_64 -c test-drm-perbuf-dumb 在 C 用例编译阶段失败。远端 Test starry x86_64 qemu / run_container 失败包含 busyboxtest-drm-perbuf-dumb,其中 busybox 看起来是既有/环境项,但 test-drm-perbuf-dumb 是本 PR 新增用例的确定性失败。

Comment thread test-suit/starryos/normal/qemu-smp1/test-drm-perbuf-dumb/c/src/main.c Outdated
Comment thread os/StarryOS/kernel/src/pseudofs/dev/card0.rs Outdated

@ZR233 ZR233 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

这版确认修掉了上一轮的 C 用例编译问题:test-drm-perbuf-dumb 现在本地 x86_64 QEMU 能完整跑过,并且 destroy 后 mmap/fb backing 生命周期覆盖也在用例里了。starry-kernel clippy 也已经恢复全绿。

仍然需要 request changes 的 blocker 是 legacy modeset 路径还没有修:SETCRTC 目前只校验 crtc_idfb_id != 0 时直接 present_fb(c.fb_id) 后返回成功;它没有校验 fb 是否存在,也没有读取/校验 count_connectorsset_connectors_ptrGETCRTC 仍然固定返回 fb_id = 0count_connectors = 0,没有从当前 modeset state 读回 legacy SETCRTC 建立的绑定。这样无效 fb/connector 会被静默接受,drmModeSetCrtc()drmModeGetCrtc() 也读不回当前 fb/connector 状态,和 Linux DRM legacy KMS 语义不一致。

建议复用现有 ModesetState 或单独维护 legacy CRTC state:SETCRTC 校验 fb 和 connector 数组,成功后写入当前 fb/connector/mode;GETCRTC 按 state 返回 fb_id、connector id 和 count_connectors。最好在 test-drm-modeset 里补一段:SETCRTCGETCRTC 应读回 fb/connector;不存在的 fb 或错误 connector 应返回失败。

本地验证记录:

  • git diff --check origin/dev...HEAD 通过
  • git merge-tree --write-tree origin/dev HEAD 通过
  • cargo fmt --check 通过
  • cargo xtask clippy --package starry-kernel 8/8 通过
  • cargo xtask starry test qemu --arch x86_64 -c test-drm-perbuf-dumb 通过,DONE: 30 pass, 0 fail

PR 当前仍是 draft。

@JosephJoshua
JosephJoshua force-pushed the drm-perbuf branch 4 times, most recently from 8e844f6 to d5cf564 Compare May 14, 2026 11:36

@ZR233 ZR233 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

这轮复查的是新 head d5cf5640d2275452134a74b3341b76e7bfbfd6bf。前面几轮提到的 dumb backing 引用保持、初始清零、IN_FORMATS / MODE_ID blob 生命周期、C 用例编译问题和 clippy 问题这次都确认已经修掉,我也把对应旧线程 resolve 掉了。

仍然需要 request changes 的 blocker 还是 legacy modeset:handle_get_crtc() 仍固定返回 fb_id = 0count_connectors = 0handle_set_crtc() 仍只校验 crtc_idfb_id != 0 时直接 present_fb(c.fb_id) 后返回成功;没有校验 fb 是否存在,也没有读取/校验 count_connectors / set_connectors_ptr,更没有把 legacy SETCRTC 建立的 fb/connector/mode state 记录下来供 GETCRTC 读回。这样不存在或已经 RMFB 的 fb、错误 connector id 都会被静默接受,drmModeSetCrtc()drmModeGetCrtc() 也读不回当前绑定,和 Linux DRM legacy KMS 语义不一致。当前 test-drm-modeset 只覆盖 SETCRTC 成功和后续 page flip/event,没有覆盖 SETCRTC -> GETCRTC readback 或 invalid fb/connector reject,所以这个问题仍会漏掉。

建议复用现有 ModesetState 或单独维护 legacy CRTC state:SETCRTC 校验 fb 和 connector 数组,成功后写入当前 fb/connector/mode;GETCRTC 按 state 返回 fb_id、connector id 和 count_connectors。同时在 test-drm-modeset 里补:SETCRTCGETCRTC 应读回 fb/connector;不存在/已删除 fb 或错误 connector 应返回失败。

本地验证记录:

  • git diff --check origin/dev...HEAD 通过
  • git merge-tree --write-tree origin/dev HEAD 通过
  • cargo fmt --check 通过
  • cargo xtask clippy --package starry-kernel 9/9 通过
  • cargo xtask starry test qemu --arch x86_64 -l 能发现 test-drm-modeset / test-drm-perbuf-dumb
  • cargo xtask starry test qemu --arch x86_64 -c test-drm-modeset 通过,DONE: 32 pass, 0 fail
  • cargo xtask starry test qemu --arch x86_64 -c test-drm-perbuf-dumb 通过,DONE: 30 pass, 0 fail

远端 CI 快照里大量 container/self-hosted job 仍在 pending;PR 当前仍是 draft。

@ZR233 ZR233 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

本轮复查确认之前的 legacy SETCRTC / GETCRTC 阻塞项已经修复:当前实现会校验 framebuffer 和 connector 数组,保存 legacy CRTC binding,并在 GETCRTC 中读回;test-drm-modeset 也覆盖了正常读回、坏 connector、RMFB 后清空绑定和已删除 fb 拒绝路径。因此旧线程已标记 resolved。

但当前 head 仍有 PR 相关 CI 失败,需要先修复后再合入。远端 CI run 25873747415 的 Test starry loongarch64 qemu / run_container 在现有 busybox case 中失败,具体为 FAIL: busybox_hwclock。这和本 PR 新增注册 /dev/rtc0 直接相关:busybox hwclock -r 不再走旧的错误输出路径,导致现有 busybox 测试的判定失败。建议同步修正 RTC 行为或更新 busybox hwclock 测试,使新增 /dev/rtc0 后 CI 能稳定通过,并补上能表达预期输出/返回值的覆盖。

本地验证:git diff --check origin/dev...HEAD 通过,cargo fmt --check 通过,cargo xtask clippy --package starry-kernel 的 9 个检查全部通过。

JosephJoshua added a commit to JosephJoshua/tgoskits that referenced this pull request May 16, 2026
Resolutions:
- linear.rs / mmap.rs: adopt dev's anchor naming convention
  (LinearBackend.anchor, Backend::new_linear_anchored). PR rcore-os#514's
  retain field/method renamed to match.
- ion.rs, ion/device.rs: pass None as the new second argument to
  DeviceMmap::Physical now that the variant carries an Option<Arc>.
- card0.rs, fb.rs, test-drm-{atomic,modeset}/main.c: keep PR rcore-os#514's
  per-buffer dumb allocation and blob-lifecycle test versions; they
  supersede the shared-scanout / simple-blob variants on dev.
- dev/mod.rs: keep both mod rtc; (PR rcore-os#514) and pub mod tpu; (dev).
@ZR233
ZR233 requested a review from luodeb May 20, 2026 03:08
@JosephJoshua
JosephJoshua marked this pull request as ready for review May 29, 2026 19:20
Copilot AI review requested due to automatic review settings May 29, 2026 19:20

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Note

Copilot was unable to run its full agentic suite in this review.

This PR strengthens StarryOS’s DRM /dev/dri/card0 behavior to more closely match Linux semantics around dumb buffers, framebuffer lifetime, and modeset blob lifetimes, and adds supporting test coverage and device plumbing.

Changes:

  • Add a new DRM regression test (test-drm-perbuf-dumb) and QEMU runners for multiple architectures.
  • Update the DRM card0 implementation to allocate per-buffer backing pages, retain mmap backing across DESTROY_DUMB, keep fb backing alive across handle destruction, and pin committed MODE_ID blobs past DESTROYPROPBLOB.
  • Add /dev/rtc0 support and adjust BusyBox hwclock test expectations.

Reviewed changes

Copilot reviewed 19 out of 19 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
test-suit/starryos/normal/qemu-smp1/test-drm-perbuf-dumb/qemu-x86_64.toml Adds QEMU launch config to run the new DRM per-buffer dumb test on x86_64.
test-suit/starryos/normal/qemu-smp1/test-drm-perbuf-dumb/qemu-riscv64.toml Adds QEMU launch config to run the new DRM per-buffer dumb test on riscv64.
test-suit/starryos/normal/qemu-smp1/test-drm-perbuf-dumb/qemu-loongarch64.toml Adds QEMU launch config to run the new DRM per-buffer dumb test on loongarch64.
test-suit/starryos/normal/qemu-smp1/test-drm-perbuf-dumb/qemu-aarch64.toml Adds QEMU launch config to run the new DRM per-buffer dumb test on aarch64.
test-suit/starryos/normal/qemu-smp1/test-drm-perbuf-dumb/c/src/test_framework.h Introduces a small C test framework for consistent PASS/FAIL accounting and output.
test-suit/starryos/normal/qemu-smp1/test-drm-perbuf-dumb/c/src/main.c New userspace DRM test validating per-buffer dumb allocation + lifecycle semantics.
test-suit/starryos/normal/qemu-smp1/test-drm-perbuf-dumb/c/CMakeLists.txt Builds/installs the new test-drm-perbuf-dumb binary.
test-suit/starryos/normal/qemu-smp1/drm/test-drm-modeset/c/src/main.c Refactors/extends modeset tests to validate GETCRTC readback and RMFB effects.
test-suit/starryos/normal/qemu-smp1/drm/test-drm-atomic/c/src/main.c Updates atomic tests to validate Linux-like propblob lifetime behavior after commit.
test-suit/starryos/normal/qemu-smp1/busybox/sh/busybox-tests.sh Makes busybox hwclock test more tolerant while still checking for plausible output.
os/StarryOS/kernel/src/syscall/mm/mmap.rs Extends device-mmap handling to optionally retain backing objects for VMA lifetime.
os/StarryOS/kernel/src/pseudofs/device.rs Extends DeviceMmap::Physical to carry an optional retainer Arc.
os/StarryOS/kernel/src/pseudofs/dev/rtc.rs Adds a minimal /dev/rtc0 device implementing RTC_RD_TIME.
os/StarryOS/kernel/src/pseudofs/dev/mod.rs Registers /dev/rtc0 in the pseudo device filesystem.
os/StarryOS/kernel/src/pseudofs/dev/ion/device.rs Adapts ION mmap to the new DeviceMmap::Physical(range, retain) signature.
os/StarryOS/kernel/src/pseudofs/dev/fb.rs Adapts framebuffer mmap to the new DeviceMmap::Physical(range, retain) signature.
os/StarryOS/kernel/src/pseudofs/dev/card1.rs Adapts card1 mmap paths/tests to the new DeviceMmap::Physical(range, retain) signature.
os/StarryOS/kernel/src/pseudofs/dev/card0.rs Major DRM behavior changes: per-buffer pages, fb retention, legacy GETCRTC state, blob pinning.
os/StarryOS/kernel/src/file/ion.rs Adapts ION buffer file mmap to the new DeviceMmap::Physical(range, retain) signature.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +977 to 991
fn handle_get_plane(arg: usize) -> VfsResult<usize> {
let ptr = arg as *mut DrmModeGetPlane;
let mut p: DrmModeGetPlane = ptr.vm_read().map_err(|_| VfsError::BadAddress)?;
if p.plane_id != PLANE_ID {
return Err(VfsError::InvalidInput);
}
p.crtc_id = CRTC_ID;
p.fb_id = 0;
p.possible_crtcs = 1;
p.gamma_size = 0;
p.count_format_types =
report_user_array(p.format_type_ptr, p.count_format_types, SUPPORTED_FORMATS)?;
ptr.vm_write(p).map_err(|_| VfsError::BadAddress)?;
Ok(0)
}
Comment on lines +888 to 915
fn handle_get_connector(arg: usize) -> VfsResult<usize> {
let ptr = arg as *mut DrmModeGetConnector;
let mut c: DrmModeGetConnector = ptr.vm_read().map_err(|_| VfsError::BadAddress)?;
if c.connector_id != CONNECTOR_ID {
return Err(VfsError::InvalidInput);
}
c.encoder_id = ENCODER_ID;
c.connector_type = DRM_MODE_CONNECTOR_VIRTUAL;
c.connector_type_id = 1;
c.connection = DRM_MODE_CONNECTED;
let (w, h) = display_resolution();
c.mm_width = w;
c.mm_height = h;
c.subpixel = 0;

let state = *self.state.lock();
let prop_vals = conn_prop_values(&state);
report_user_array(c.props_ptr, c.count_props, CONN_PROPS)?;
report_user_array(c.prop_values_ptr, c.count_props, &prop_vals)?;
c.count_props = CONN_PROPS.len() as u32;
c.count_encoders = report_user_array(c.encoders_ptr, c.count_encoders, &[ENCODER_ID])?;

ptr.vm_write(c).map_err(|_| VfsError::BadAddress)?;
Ok(0)
if c.modes_ptr != 0 && c.count_modes > 0 {
let p = c.modes_ptr as *mut DrmModeModeInfo;
p.vm_write(current_mode())
.map_err(|_| VfsError::BadAddress)?;
}
c.count_modes = 1;
c.count_props = 0;

ptr.vm_write(c).map_err(|_| VfsError::BadAddress)?;
Ok(0)
}
Comment on lines 602 to +617
let size = (pitch as u64)
.checked_mul(c.height as u64)
.ok_or(VfsError::InvalidInput)?;
if size > 256 * 1024 * 1024 {
return Err(VfsError::InvalidInput);
if size as usize > DUMB_BUFFER_MAX_SIZE {
return Err(VfsError::NoMemory);
}
c.pitch = pitch;
c.size = size;
let handle = self.next_dumb_handle.fetch_add(1, Ordering::Relaxed);

let alloc_size =
((size as usize) + PageSize::Size4K as usize - 1) & !((PageSize::Size4K as usize) - 1);
let paddr = self.alloc_dumb_pages(alloc_size);
// Each buffer gets its own page-aligned `GlobalPage`. No shared
// pool, so we don't fail on early-boot fragmentation on arches
// whose allocator can't satisfy one large contiguous request
// after driver probe.
let size_aligned = (size as usize).next_multiple_of(PAGE_SIZE_4K);
let pages = size_aligned / PAGE_SIZE_4K;
let mut backing =
GlobalPage::alloc_contiguous(pages, PAGE_SIZE_4K).map_err(|_| VfsError::NoMemory)?;
Comment on lines 508 to +511
let dumbs = self.dumbs.lock();
for (_, buf) in dumbs.iter() {
if offset == buf.offset
&& let Some(paddr) = buf.paddr
{
return DeviceMmap::Physical(PhysAddrRange::from_start_size(
paddr,
(length.min(buf.size)) as usize,
));
}
}
DeviceMmap::None
let Some(b) = dumbs.values().find(|b| b.offset == offset) else {
return DeviceMmap::None;
};

@mai-team-app mai-team-app Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

本轮复查的是 head bca534db626ea5e8db3842517e8cb372f52e65ed(2 commits)。

PR 概述

本 PR 将 DRM /dev/dri/card0 的 dumb buffer 模型从「所有 buffer 共享同一段 axdisplay scanout」改为 per-buffer GlobalPage 独立分配,并引入 GEM 风格的引用计数语义。同时新增 /dev/rtc0LegacyCrtcStateMODE_ID blob pinning、IN_FORMATS 拆分到 system_blobs,以及完整的 test-drm-perbuf-dumb C 测试。

之前阻塞项确认已修复

ZR233 在之前 8 轮 review 中提出的所有阻塞问题在当前 head 均已修复:

  1. framebuffer backing 生命周期ADDFB2 现在创建 Framebuffer { size, pages } 结构体,持有 Arc<GlobalPage> 克隆。DESTROY_DUMB 仅移除 handle 表中的强引用,fb 持有的引用继续存活。✅
  2. dumb buffer 未清零handle_create_dumballoc_contiguous 后调用 backing.zero()。✅
  3. IN_FORMATS blob 可被用户删除:已拆分到 system_blobshandle_destroy_blob 拒绝删除系统 blob。✅
  4. MODE_ID blob 生命周期mode_id_blob_ref 持有已提交 blob 的 ArcDESTROYPROPBLOB 后仍可通过该引用访问。✅
  5. Clippy 失败cargo xtask clippy --package starry-kernel 14/14 通过。✅
  6. legacy SETCRTC/GETCRTC 语义:新增 LegacyCrtcStateSETCRTC 校验 fb/connector 数组,GETCRTC 读回绑定状态,RMFB 清除绑定。✅
  7. C 测试编译问题:当前编译运行正常。✅
  8. busybox hwclock CI 失败:hwclock 测试改为容错匹配,接受成功读取年份或含 hwclock 的错误消息。✅

代码审查

实现质量良好:

  • DumbBuffer 使用 Arc<GlobalPage> 正确建模 GEM refcount
  • Framebuffer 持有独立 Arc 克隆,确保 DESTROY_DUMB 后 fb backing 仍存活
  • LegacyCrtcState 将 legacy modeset 与 atomic state 分离
  • present_fb 快照模式避免在 framebuffer_flush 期间持有锁
  • mode_id_blob_ref 正确 pin 住已提交的 MODE_ID blob
  • Backend::new_linear_anchored 路径通过 retainer 正确保持 VMA 中的页面存活
  • GETCONNECTORcount_props 从报告 CONN_PROPS 改为 0,但 libdrm 通过 OBJ_GETPROPERTIES 获取属性表面,不影响功能

验证结果

验证项 结果
cargo fmt --check ✅ 通过
cargo xtask clippy --package starry-kernel ✅ 14/14 通过
cargo xtask starry test qemu --arch x86_64 -c test-drm-perbuf-dumb ✅ 30 pass, 0 fail
cargo xtask starry test qemu --arch x86_64 -c drm(已有 DRM 测试) ✅ 14 pass, 0 fail

QEMU 验证详情test-drm-perbuf-dumb 覆盖了完整的 per-buffer dumb 路径:

  • 两次 CREATE_DUMB 拿到独立 handle
  • 两次 MAP_DUMB 返回不同 offset
  • 两个 mmap 区域物理隔离(写 buf2 不影响 buf1)
  • 梯度像素写入验证
  • 两次 ADDFB2 拿到不同 fb_id
  • 两次 atomic commit 在 fb1/fb2 之间翻页
  • DESTROY_DUMB 后 mmap 仍然可读写
  • DESTROY_DUMB 后 atomic commit 仍能翻页(GEM 生命周期验证)

重复/重叠分析

搜索了 open PR,未发现与 DRM dumb buffer、card0 或相关模块重叠的 PR。PR #1038(nginx CI)和 PR #1036(K230 KPU)均与本 PR 无关。

注意事项

  • PR 当前 mergeable_state=dirty,需要 rebase 到最新 dev 以解决冲突后才能合入。
  • /dev/rtc0RTC_RD_TIME 只返回 wall time,tm_wday/tm_yday 固定为 0,后续可扩展。
  • PRIME 路径 (HANDLE_TO_FD/FD_TO_HANDLE) 当前为占位实现,留给后续 PR。

结论

所有之前阻塞的问题均已修复,验证通过,无新增阻塞问题。建议 APPROVE(待 rebase 解决冲突后)。

Powered by mimo-v2.5-pro

Rebase drm-perbuf onto upstream dev:
- ax_hal:: -> ax_runtime::hal:: import renames
- Drop kcov DeviceMmap variants removed upstream
- Incorporate upstream PROT_NONE/USER flag logic
- Adapt busybox hwclock test for /dev/rtc0 presence

@mai-team-app mai-team-app Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

本轮复查的是 head 34c97fb9ac13dcad7ce64744b9d8e4c545cd009a(2 commits)。

PR 概述

本 PR 将 DRM /dev/dri/card0 的 dumb buffer 模型从「所有 buffer 共享同一段 axdisplay scanout」改为 per-buffer GlobalPage 独立分配,并引入 GEM 风格的引用计数语义。同时新增 /dev/rtc0LegacyCrtcStateMODE_ID blob pinning、IN_FORMATS 拆分到 system_blobs,以及完整的 test-drm-perbuf-dumb C 测试。

之前阻塞项确认已修复

ZR233 在之前多轮 review 中提出的所有阻塞问题在当前 head 均已修复:

  1. framebuffer backing 生命周期ADDFB2 创建 Framebuffer { size, pages } 结构体,持有 Arc<GlobalPage> 克隆。DESTROY_DUMB 仅移除 handle 表中的强引用,fb 持有的引用继续存活。✅
  2. dumb buffer 未清零handle_create_dumballoc_contiguous 后调用 backing.zero()。✅
  3. IN_FORMATS blob 可被用户删除:已拆分到 system_blobshandle_destroy_blob 拒绝删除系统 blob。✅
  4. MODE_ID blob 生命周期mode_id_blob_ref 持有已提交 blob 的 ArcDESTROYPROPBLOB 后仍可通过该引用访问。✅
  5. Clippy 失败cargo xtask clippy --package starry-kernel 13/13 通过。✅
  6. legacy SETCRTC/GETCRTC 语义LegacyCrtcState 正确维护,SETCRTC 校验 fb/connector 数组,GETCRTC 读回绑定状态,RMFB 清除绑定。✅
  7. C 测试编译问题:当前编译运行正常。✅
  8. busybox hwclock CI 失败:hwclock 测试改为容错匹配,接受成功读取年份或含 hwclock 的错误消息。✅

代码审查

实现质量良好:

  • DumbBuffer 使用 Arc<GlobalPage> 正确建模 GEM refcount
  • Framebuffer 持有独立 Arc 克隆,确保 DESTROY_DUMB 后 fb backing 仍存活
  • LegacyCrtcState 将 legacy modeset 与 atomic state 分离
  • present_fb 快照模式避免在 framebuffer_flush 期间持有锁
  • mode_id_blob_ref 正确 pin 住已提交的 MODE_ID blob
  • Backend::new_linear_anchored 路径通过 retainer 正确保持 VMA 中的页面存活
  • DeviceMmap::Physical 增加可选 retainer 参数,fb.rs / card1.rs / ion 等调用点填 None,行为不变
  • mmap 正确将 length 限制在 buffer size 范围内

验证结果

验证项 结果
git diff --check origin/dev...HEAD ✅ 通过
git merge-tree --write-tree origin/dev HEAD ✅ 通过(无冲突)
cargo fmt --check ✅ 通过
cargo xtask clippy --package starry-kernel ✅ 13/13 通过
test-drm-perbuf-dumb x86_64 QEMU ✅ 30 pass, 0 fail
drm 已有 DRM 测试 x86_64 QEMU ✅ 14 pass, 0 fail

QEMU 验证详情test-drm-perbuf-dumb 覆盖了完整的 per-buffer dumb 路径:

  • 两次 CREATE_DUMB 拿到独立 handle
  • 两次 MAP_DUMB 返回不同 offset
  • 两个 mmap 区域物理隔离(写 buf2 不影响 buf1)
  • 梯度像素写入验证
  • 两次 ADDFB2 拿到不同 fb_id
  • 两次 atomic commit 在 fb1/fb2 之间翻页
  • DESTROY_DUMB 后 mmap 仍然可读写
  • DESTROY_DUMB 后 atomic commit 仍能翻页(GEM 生命周期验证)

注意事项

  • PR 当前 mergeable_state=blocked,可能需要 rebase 到最新 dev。
  • /dev/rtc0RTC_RD_TIME 只返回 wall time,tm_wday/tm_yday 固定为 0,后续可扩展。
  • PRIME 路径 (HANDLE_TO_FD/FD_TO_HANDLE) 当前为占位实现,留给后续 PR。

结论

所有之前阻塞的问题均已修复,本地验证通过,QEMU 测试全绿。建议 APPROVE。

Powered by mimo-v2.5-pro

@ZR233
ZR233 merged commit 754f60d into rcore-os:dev May 31, 2026
51 checks passed
@github-actions github-actions Bot mentioned this pull request Jun 3, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants