5.3.1 PRIME 的两座桥:GEM ↔ dma-buf 桥接回调与 fd/handle 转换
5.2 节 分析 了dma-buf 这套「跨设备缓冲区共享」的通用机制但它始终停在 dma-buf 自己的抽象层。回到 DRM/GEM 的场景用户态访问 BO 的接口是一个进程内的 GEMhandle一个 32 位整数渲染时用 handle 引用 BO提交命令时用 handle 索引。可 handle 只在本进程本设备有意义一旦要把 BO 交给另一个进程、另一块 GPU就必须换成能跨进程传递的 dma-buffd。然后 fd 要变成importer 进程中的 handle 才能被用户态访问。PRIME 就是 GEM 世界与 dma-buf 世界之间的双向桥它把「进程私有的 handle」翻译成「可传递的 fd」导出又把别处传来的「fd」翻译回「本进程的 handle」导入。用户态只需两个 ioctl内核则用一组桥接回调把两套对象模型的生命周期、引用计数、缓存一一对齐。1. 两个 ioctl两座桥用户态的全部入口就是两个对称的 ioctlioctl方向内核入口作用DRM_IOCTL_PRIME_HANDLE_TO_FD导出drm_prime_handle_to_fd_ioctl→drm_gem_prime_handle_to_fd本进程 handle → 可传递的 dma-buf fdDRM_IOCTL_PRIME_FD_TO_HANDLE导入drm_prime_fd_to_handle_ioctl→drm_gem_prime_fd_to_handle别处传来的 fd → 本进程 handle两个 ioctl 都留了「驱动可覆盖」的回调若dev-driver-prime_handle_to_fd/prime_fd_to_handle非空则用驱动自己的否则用 DRM 核心的默认实现。绝大多数驱动直接用默认的。进程 B / GPU-1进程 A / GPU-0HANDLE_TO_FDSCM_RIGHTS 传递 fdFD_TO_HANDLEGEM handledma-buf fddma-buf fdGEM handle同一个 struct dma_buf同一块后端存储2. 导出桥handle → fddrm_gem_prime_handle_to_fd()本身只做「申请 fd → 拿 dma_buf → 安装 fd」三步intdrm_gem_prime_handle_to_fd(structdrm_device*dev,structdrm_file*file_priv,uint32_thandle,uint32_tflags,int*prime_fd){structdma_buf*dmabuf;intfdget_unused_fd_flags(flags);/* 1. 预留一个空 fd */...dmabufdrm_gem_prime_handle_to_dmabuf(dev,file_priv,handle,flags);/* 2. handle→dma_buf */...fd_install(fd,dmabuf-file);/* 3. 把 dma_buf 的 file 装到 fd 上 */*prime_fdfd;return0;}真正有讲究的是第 2 步drm_gem_prime_handle_to_dmabuf()它按三种情况决定 dma_buf 从哪来/* 情况一这个 GEM 对象本身就是从别处导入来的 → 复用原始 dma-buf */if(obj-import_attach){dmabufobj-import_attach-dmabuf;get_dma_buf(dmabuf);gotoout_have_obj;}/* 情况二之前已经导出过 → 复用缓存的 dma_buf不重复创建 */if(obj-dma_buf){get_dma_buf(obj-dma_buf);dmabufobj-dma_buf;gotoout_have_obj;}/* 情况三第一次导出 → 真正创建并注册 dma_buf */dmabufexport_and_register_object(dev,obj,flags);这三个分支保证了一条关键不变量——同一个 GEM 对象在其生命周期内只对应唯一一个 dma_buf情况一import_attach非空这块 BO 是导入来的「影子对象」导出它时不能再包一层而要把最初的原始 dma-buf 原样交出去——否则会出现「dma-buf 套 GEM 套 dma-buf」的荒谬嵌套。情况二obj-dma_buf已缓存曾经导出过直接复用并get_dma_buf加引用避免同一 BO 产生两个互不相干的 dma_buf。情况三首次导出才走export_and_register_object内部最终调obj-funcs-export默认是drm_gem_prime_export真正创建 dma_buf并把它缓存进obj-dma_buf。drm_gem_prime_export()就是那个「真正创建」的默认实现它把 GEM 对象填进标准的dma_buf_export_infostructdma_buf*drm_gem_prime_export(structdrm_gem_object*obj,intflags){structdma_buf_export_infoexp_info{.exp_nameKBUILD_MODNAME,.opsdrm_gem_prime_dmabuf_ops,/* GEM 专用的 dma_buf_ops */.sizeobj-size,.flagsflags,.privobj,/* dma_buf-priv 指回 GEM 对象 */.resvobj-resv,/* 共用同一个 reservation object */};returndrm_gem_dmabuf_export(dev,exp_info);}两个字段值得记住priv obj建立了「dma_buf → GEM 对象」的反向指针前几节 amdgpu 里gem_to_amdgpu_bo(dma_buf-priv)就靠它resv obj-resv让 dma-buf 与 GEM 对象共享同一把同步锁与 fence 容器这是隐式同步6.3能跨设备生效的根基。ops drm_gem_prime_dmabuf_ops则是这座桥的另一半——它把 dma-buf 的通用回调转接到 GEM 的drm_gem_object_funcsdma_buf_ops 回调GEM 桥接实现最终委派到attachdrm_gem_map_attachobj-funcs-pinmap_dma_bufdrm_gem_map_dma_bufobj-funcs-get_sg_tableunmap_dma_bufdrm_gem_unmap_dma_buf——releasedrm_gem_dmabuf_releaseobj引用释放mmapdrm_gem_dmabuf_mmapobj-funcs-mmapvmap/vunmapdrm_gem_dmabuf_vmapobj-funcs-vmapdma-buf core 通过drm_gem_prime_dmabuf_ops敲门最终都落到某个drm_gem_object_funcs上。这也解释了 5.2.4 里 amdgpu 的map_dma_buf为何最终会走到 GEM 的get_sg_table——中间正是这张转接表在牵线。若驱动的get_sg_table未实现drm_gem_map_attach会直接返回-ENOSYS即拒绝导出到别的设备。3. 导入桥fd → handle反方向的drm_gem_prime_fd_to_handle()要把一枚陌生的 fd 变成本进程的 handleintdrm_gem_prime_fd_to_handle(structdrm_device*dev,structdrm_file*file_priv,intprime_fd,uint32_t*handle){structdma_buf*dma_bufdma_buf_get(prime_fd);/* fd → struct dma_buf */.../* 1. 查本进程的导入缓存这个 dma_buf 之前导入过吗 */retdrm_prime_lookup_buf_handle(file_priv-prime,dma_buf,handle);if(ret0)gotoout_put;/* 命中 → 复用旧 handle *//* 2. 没见过 → 调驱动的 import 回调造一个 GEM 对象 */if(dev-driver-gem_prime_import)objdev-driver-gem_prime_import(dev,dma_buf);elseobjdrm_gem_prime_import(dev,dma_buf);.../* 3. 建立 GEM 对象 ↔ dma_buf 的双向引用 */if(!obj-dma_buf){obj-dma_bufdma_buf;get_dma_buf(dma_buf);}/* 4. 为这个 GEM 对象分配本进程 handle并写入缓存 */retdrm_gem_handle_create_tail(file_priv,obj,handle);retdrm_prime_add_buf_handle(file_priv-prime,dma_buf,*handle);...}关键仍是缓存 唯一性file_priv-prime是每个 DRM file 私有的双向缓存dma_buf ↔ handle。同一个 dma_buf 在同一进程被导入两次第 1 步就会命中缓存返回同一个 handle——保证「一块共享 buffer 在一个进程里只有一个 handle」。第 2 步的drm_gem_prime_import()转调核心的drm_gem_prime_import_dev()它才是真正「把 dma_buf 变成 GEM 对象」的地方其中藏着一个重要优化structdrm_gem_object*drm_gem_prime_import_dev(structdrm_device*dev,structdma_buf*dma_buf,structdevice*attach_dev){/* 自导入优化如果这个 dma_buf 正是本 dev 自己导出的 * 不必 attach直接给原 GEM 对象加引用即可 */if(drm_gem_is_prime_exported_dma_buf(dev,dma_buf)){objdma_buf-priv;drm_gem_object_get(obj);returnobj;}if(!dev-driver-gem_prime_import_sg_table)returnERR_PTR(-EINVAL);/* 正常路径attach → map 拿 sg_table → 让驱动据此造 GEM 对象 */attachdma_buf_attach(dma_buf,attach_dev);get_dma_buf(dma_buf);sgtdma_buf_map_attachment_unlocked(attach,DMA_BIDIRECTIONAL);objdev-driver-gem_prime_import_sg_table(dev,attach,sgt);/* 驱动回调 */obj-import_attachattach;/* 记住「我是导入来的」及其 attachment */obj-resvdma_buf-resv;/* 共用源 dma-buf 的 resv → 同步能跨设备生效 */returnobj;}三个要点串起了前几节自导入优化drm_gem_is_prime_exported_dma_buf把自己导出的 dma-buf 再导入回来只增加 GEM 对象引用、不增加 dma-buf 的f_count——避免自己 attach 自己的病态循环。这与第 2 节导出侧「情况一」互为镜像。attach map 复用 5.2.4 的机制导入桥并不自己发明轮子而是老老实实走dma_buf_attach → dma_buf_map_attachment拿到sg_table再交给驱动的gem_prime_import_sg_table据此构造一个「影子 GEM 对象」。import_attach 共用resvobj-import_attach标记这是导入对象第 2 节导出侧据此复用原始 dma-bufobj-resv dma_buf-resv让影子对象与源 buffer 共享 fence 容器——这是跨设备隐式同步6.3成立的前提。驱动还须在其free回调里调drm_prime_gem_destroy()收尾 attach。4. 一张全景图两套对象模型如何对齐把导出与导入合起来看PRIME 的本质是维护「GEM 对象 ↔ dma_buf」的一一对应与引用计数dma-buf 世界GEM 世界export: funcs-export / drm_gem_prime_exportimport: gem_prime_import_sg_tablehandle ↔ dma_buf 缓存file_priv-primefd ↔ handledrm_gem_objectobj-dma_buf缓存obj-import_attach若导入obj-resvstruct dma_bufdma_buf-priv objdma_buf-ops drm_gem_prime_dmabuf_opsdma_buf-resv obj-resv进程内 handle跨进程 fdpriv/dma_buf互指dma_buf 用priv指回 GEM 对象GEM 对象用dma_buf缓存反向引用二者一一对应。resv共用导出时dma_buf-resv obj-resv导入时obj-resv dma_buf-resv最终跨设备的两个 GEM 影子对象共享同一个dma_resv——同步语义得以贯通。两级缓存file_priv-prime管「fd/dma_buf ↔ handle」obj-dma_buf管「GEM 对象 ↔ dma_buf」共同保证任何一块共享 buffer 在任一进程、任一方向都不会分裂出多个副本。5. 小结与延伸PRIME 是 GEM 与 dma-buf 之间的双向桥HANDLE_TO_FD导出、FD_TO_HANDLE导入把「进程私有 handle」与「可传递 fd」互相翻译。drm_gem_prime_dmabuf_ops是转接表dma-buf 的通用回调attach/map/mmap/vmap经它统一落到 GEM 的drm_gem_object_funcsmap_dma_buf最终委派get_sg_table——这正是 5.2.4 amdgpu 那条回调链的中枢。唯一性与引用计数是灵魂obj-dma_buf缓存、import_attach复用、file_priv-prime双向缓存、自导入优化、共用resv五条机制共同保证「一块 buffer 在一个进程里只有一个 handle、一个 GEM 对象只对应一个 dma_buf」。到这里PRIME 的核心桥接已经清晰但还有一个实际问题gem_prime_import_sg_table、get_sg_table、pin/unpin这些回调普通驱动要不要每个都自己写一遍对大量基于系统内存的简单驱动DRM 提供了开箱即用的GEM shmem helper把这套共享路径全部实现好了。这正是[5.3.2 GEM shmem helper 的共享路径]的主题。相关阅读dma-buf 的 attach/map 机制见 5.2.4get_sg_table/pin/unpin等 GEM 回调的语义见 gem_object_funcs.md共用resv带来的隐式同步见 6.3 dma_resv。

相关新闻

音游高难度谱面攻关:从谱面拆解到肌肉记忆的系统方法论

音游高难度谱面攻关:从谱面拆解到肌肉记忆的系统方法论

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/9/3 15:43:50 阅读更多 →
STM32 硬件过流保护实战:比较器直连 BKIN,纳秒级关断不靠软件

STM32 硬件过流保护实战:比较器直连 BKIN,纳秒级关断不靠软件

烧掉第三对 MOS 管的那天下午,我终于承认软件保护是靠不住的。 当时的保护方案写得挺完整:ADC 定时采母线电流,超过阈值就在中断里调 HAL_TIM_PWM_Stop() 关掉六路输出。逻辑没问题,测试也过了。但真正短路的时候,从电…

2026/9/3 15:43:50 阅读更多 →
Codex 企业级落地,构建安全可控的 AI 编程协作流程

Codex 企业级落地,构建安全可控的 AI 编程协作流程

从“野蛮生长”到“安全可控”:企业级 Codex 落地规范 当 AI 编程助手从个人玩具转变为团队标配,技术管理者面临的挑战也随之升级。我们不再仅仅关注“它能不能写出代码”,而是更关心“它会不会泄露核心逻辑”、“生成的代码是否合规”以及“…

2026/9/3 15:42:49 阅读更多 →

最新新闻

工厂能源智能管控:小白也能看懂的大模型应用(收藏必备)

工厂能源智能管控:小白也能看懂的大模型应用(收藏必备)

工厂能源管理正经历从传统EMS到智能管控的范式转移。文章介绍了工厂能源智能管控系统的五层架构(感知-数据-预测-决策-执行),重点解析了多模态预测技术栈(数据源、特征工程、融合方法、模型选型、评估更新)和深度强化学…

2026/9/3 16:26:25 阅读更多 →
别再瞎拼论文图表[特殊字符]‍♀️Paperxie科研绘图!30秒出学术原图

别再瞎拼论文图表[特殊字符]‍♀️Paperxie科研绘图!30秒出学术原图

终于不用为了论文图表熬夜啃绘图软件了!!😭 谁懂本科生的痛: 论文正文、综述、查重全部搞定,最后栽在图表配图上! Visio、Origin难学到崩溃,网上找的图片要么有水印、要么模糊失真、版权风险…

2026/9/3 16:26:25 阅读更多 →
《三角符文》暗世界理论解析:从游戏叙事到世界观构建

《三角符文》暗世界理论解析:从游戏叙事到世界观构建

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/9/3 16:26:25 阅读更多 →
告别手搓丑图❗Paperxie科研绘图封神|论文配图一键搞定

告别手搓丑图❗Paperxie科研绘图封神|论文配图一键搞定

谁懂啊!论文内容写满分,偏偏栽在配图上😭 辛辛苦苦写完论文正文、打磨好逻辑和重复率,最后被粗糙难看的配图、不规范的图表、杂乱的流程图拉低整体档次! 不会PS、不会专业绘图软件、零基础看不懂操作教程&#xff0c…

2026/9/3 16:26:25 阅读更多 →
推翻流水账综述❗PaperxieAI综述才是本科生正确打开方式

推翻流水账综述❗PaperxieAI综述才是本科生正确打开方式

奉劝所有本科生!别再用老式方法写文献综述了🙅 之前写综述我真的纯纯无效熬夜! 花两三天找几十篇文献,逐篇摘抄观点、拼接段落,写完满满几千字,结果被导师一句话打回:没有研究逻辑、只是文献搬…

2026/9/3 16:26:25 阅读更多 →
市场情绪分析实战:从大盘到板块的联动逻辑与轮动节奏识别

市场情绪分析实战:从大盘到板块的联动逻辑与轮动节奏识别

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/9/3 16:25:25 阅读更多 →

日新闻

AI智能体辅助JS逆向:从V8环境搭建到补环境实战

AI智能体辅助JS逆向:从V8环境搭建到补环境实战

先别急着点开,这不是劝退文,而是想讲清楚一件事:用 AI 做逆向值不值得学?如果要用,怎么搭一套“V8 环境 AI 智能体”来提升效率。最近逆向圈、爬虫圈都在聊 AI Agent、AST 工程逆向、JS 逆向这些词,很多新手…

2026/9/3 0:00:29 阅读更多 →
安卓设备通过修改机型信息解锁游戏高帧率:原理、操作与风险指南

安卓设备通过修改机型信息解锁游戏高帧率:原理、操作与风险指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/9/3 0:00:29 阅读更多 →
ARM版OpenJDK 11安装部署全攻略:下载、配置与避坑指南

ARM版OpenJDK 11安装部署全攻略:下载、配置与避坑指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/9/3 0:00:29 阅读更多 →

周新闻

备战数据库管理工程师校招:索引、事务、备份恢复核心考点解析

备战数据库管理工程师校招:索引、事务、备份恢复核心考点解析

每年校招季我都会接触不少准备数据库方向笔试的同学,看到最多的状态就是:简历上写着“熟悉 MySQL”“了解索引优化”,一碰到数据库管理工程师的笔试卷,却在索引、事务、锁、备份恢复这些题目上翻车。网易这套 2018 校园招聘数据库…

2026/9/3 4:22:22 阅读更多 →
数字电路时序基石:深入理解建立时间与保持时间

数字电路时序基石:深入理解建立时间与保持时间

1. 这不是“背公式”的事:时间参数到底在约束什么你翻过数字电路教材,一定见过这两个词:建立时间(Setup Time)和保持时间(Hold Time)。它们常被并列写在触发器(Flip-Flop&#xff09…

2026/9/3 4:22:01 阅读更多 →
蓝桥杯国赛超声波测距机:从单片机原理到嵌入式系统实战

蓝桥杯国赛超声波测距机:从单片机原理到嵌入式系统实战

1. 项目缘起:从赛题到超声波测距机的诞生第八届蓝桥杯单片机设计与开发国赛的题目,我至今记忆犹新。它没有直接给出一个花哨的名字,而是用“超声波测距机”这个朴实无华的功能描述,精准地勾勒出了考核的核心。对于当时备赛的我而言…

2026/9/3 4:22:59 阅读更多 →

月新闻

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能分类:[AI/大模型]细分主题:AI 增强型 CI/CD 流水线自动化与 GitOps 实践:Agent 工作流、工具调用与任务拆解:从原型到生产的验收清单很多团队在尝试用大…

2026/9/3 4:17:49 阅读更多 →
容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场

容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场

容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场分类:[工程技术]细分主题:Kubernetes 生产环境运维与排障实战:可复制的项目复盘模板与决策记录大部分团队的事故复盘报告,最后都变成了躺在 Confluence 或钉…

2026/9/3 4:18:56 阅读更多 →
容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步

容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步

容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步分类:[工程技术]细分主题:Docker 容器化技术与镜像安全管理:核心链路的逐步实现与关键代码取舍面对一个积累了五六年历史包袱的单体架构应用(包含 Web 接口、后台…

2026/9/3 4:21:44 阅读更多 →