02 Xe GPUVM 数据结构与“继承“模型
系列Xe 驱动中drm_gpuvm的实现分析深度定位架构 关键路径。本篇聚焦结构内嵌、类型转换与 flags 复用。1. C 语言里的继承内嵌 container_ofLinux 内核没有 C 的继承机制但通过“把父类结构作为子类的第一个成员”container_of宏可以实现等价效果。drm_gpuvm框架就是围绕这一模式设计的——它的注释里明确写着Typically, this structure is embedded in bigger driver structures.Xe 严格遵循这个约定形成三层平行的父—子结构对核心层父Xe子语义struct drm_gpuvmstruct xe_vm整个 GPU 地址空间struct drm_gpuvastruct xe_vma单个 VA 映射struct drm_gpuva_opstruct xe_vma_op单条 bind 操作内嵌为首成员内嵌为首成员内嵌为首成员xe_vmdrm_gpuvm gpuvmxe_vmadrm_gpuva gpuvaxe_vma_opdrm_gpuva_op basedrm_gpuvmdrm_gpuvadrm_gpuva_op2. 三对结构的内嵌细节2.1xe_vm⊃drm_gpuvmgpuvm是xe_vm的第一个字段见 xe_vm_types.hstructxe_vm{/** gpuvm: base GPUVM used to track VMAs */structdrm_gpuvmgpuvm;/** svm: Shared virtual memory state */struct{structdrm_gpusvmgpusvm;...}svm;...};放在首位不是硬性要求container_of支持任意偏移但放首位可让xe_vm xe_vm.gpuvm转型时偏移为 0也便于阅读。2.2xe_vma⊃drm_gpuva见 xe_vm_types.hstructxe_vma{/** gpuva: Base GPUVA object */structdrm_gpuvagpuva;...u8 tile_mask;// 期望在哪些 tile 建立绑定u8 tile_present;// 哪些 tile 已建立u8 tile_invalidated;// 哪些 tile 的绑定已失效structxe_vma_mem_attrattr;// PAT/atomic/首选内存位置};父结构drm_gpuva提供了所有与硬件无关的字段见 drm_gpuvm.hstructdrm_gpuva{structdrm_gpuvm*vm;// 所属地址空间structdrm_gpuvm_bo*vm_bo;// (VM,BO) 连接点第 5 篇enumdrm_gpuva_flagsflags;// 标志位含用户位见 §4struct{u64 addr;u64 range;}va;// VA 起址 长度struct{u64 offset;structdrm_gem_object*obj;...}gem;// 背后 BOstruct{structrb_nodenode;...}rb;// 区间树节点};2.3xe_vma_op⊃drm_gpuva_op见 xe_vm_types.hstructxe_vma_op{structdrm_gpuva_opbase;// ← 父MAP/REMAP/UNMAP/PREFETCH 通用描述structlist_headlink;// 挂到 xe_vma_ops.listenumxe_vma_op_flagsflags;// COMMITTED / PREV_COMMITTED / NEXT_COMMITTEDu8 tile_mask;union{// 按 op 类型区分的私有数据structxe_vma_op_mapmap;structxe_vma_op_remapremap;structxe_vma_op_prefetchprefetch;structxe_vma_op_map_rangemap_range;...};};base由核心层的 split/merge 算法填充第 6 篇union里的私有字段由 Xe 在解析阶段填充第 7 篇。3. 转型辅助一组container_of内联函数Xe 把所有子←→父转型封装成内联函数集中在 xe_vm.h// gpuvm → xe_vmstaticinlinestructxe_vm*gpuvm_to_vm(structdrm_gpuvm*gpuvm){returncontainer_of(gpuvm,structxe_vm,gpuvm);}// gpuva → xe_vmastaticinlinestructxe_vma*gpuva_to_vma(structdrm_gpuva*gpuva){returncontainer_of(gpuva,structxe_vma,gpuva);}// gpuva → xe_vm跨两层先取 gpuva-vm再转型staticinlinestructxe_vm*gpuva_to_vm(structdrm_gpuva*gpuva){returngpuvm_to_vm(gpuva-vm);}// drm_gpuva_op → xe_vma_opstaticinlinestructxe_vma_op*gpuva_op_to_vma_op(structdrm_gpuva_op*op){returncontainer_of(op,structxe_vma_op,base);}// xe_vma → xe_vm经由内嵌 gpuva 的 vm 指针staticinlinestructxe_vm*xe_vma_vm(structxe_vma*vma){returncontainer_of(vma-gpuva.vm,structxe_vm,gpuvm);}使用场景对照核心层回调把struct drm_gpuvm *传回给 Xe → 用gpuvm_to_vm()拿回xe_vm遍历区间树得到struct drm_gpuva *→ 用gpuva_to_vma()拿回xe_vma遍历 op 列表得到struct drm_gpuva_op *→ 用gpuva_op_to_vma_op()拿回xe_vma_op。这正是第 1 篇提到的双向转型核心层只认父类型Xe 在边界处转回子类型。4. 字段访问器屏蔽父结构布局Xe 没有让代码到处直接写vma-gpuva.va.addr而是包了一层访问器并在文档注释里说明目的是便于将来改实现见 xe_vm.hstaticinlineu64xe_vma_start(structxe_vma*vma){returnvma-gpuva.va.addr;}staticinlineu64xe_vma_size(structxe_vma*vma){returnvma-gpuva.va.range;}staticinlineu64xe_vma_end(structxe_vma*vma){returnxe_vma_start(vma)xe_vma_size(vma);}staticinlineu64xe_vma_bo_offset(structxe_vma*vma){returnvma-gpuva.gem.offset;}staticinlinestructxe_bo*xe_vma_bo(structxe_vma*vma){return!vma-gpuva.gem.obj?NULL:container_of(vma-gpuva.gem.obj,structxe_bo,ttm.base);// 又一次继承转型}注意xe_vma_bo()里再次出现继承模式drm_gem_object内嵌在ttm_buffer_object里ttm_buffer_object又内嵌在xe_bo里于是gem.obj → xe_bo也靠container_of。5. flags 复用把驱动私有状态塞进DRM_GPUVA_USERBITS这是 Xe 用drm_gpuvm的一处巧思。核心层在drm_gpuva.flags里只定义了 3 个位见 drm_gpuvm.henumdrm_gpuva_flags{DRM_GPUVA_INVALIDATED(10),// 背后 BO 已失效DRM_GPUVA_SPARSE(11),// 稀疏映射NULL 映射DRM_GPUVA_USERBITS(12),// ← 用户可用位起点};从DRM_GPUVA_USERBITSbit 2往上全部留给驱动。Xe 就在这里定义了 11 个私有标志见 xe_vm_types.h#defineXE_VMA_READ_ONLYDRM_GPUVA_USERBITS// bit 2 只读#defineXE_VMA_DESTROYED(DRM_GPUVA_USERBITS1)// bit 3 已销毁#defineXE_VMA_ATOMIC_PTE_BIT(DRM_GPUVA_USERBITS2)// bit 4 原子 PTE#defineXE_VMA_PTE_4K(DRM_GPUVA_USERBITS3)// bit 5 ┐#defineXE_VMA_PTE_2M(DRM_GPUVA_USERBITS4)// bit 6 ├ 当前 PTE 页尺寸#defineXE_VMA_PTE_1G(DRM_GPUVA_USERBITS5)// bit 7 │#defineXE_VMA_PTE_64K(DRM_GPUVA_USERBITS6)// bit 8 ┘#defineXE_VMA_PTE_COMPACT(DRM_GPUVA_USERBITS7)// bit 9 紧凑 PTE#defineXE_VMA_DUMPABLE(DRM_GPUVA_USERBITS8)// bit 10 可被 coredump#defineXE_VMA_SYSTEM_ALLOCATOR(DRM_GPUVA_USERBITS9)// bit 11 CPU 地址镜像/SVM#defineXE_VMA_MADV_AUTORESET(DRM_GPUVA_USERBITS10)// bit 12 madvise 自动复位好处这些状态与每个 VMA 一一对应直接复用父结构已有的flags字段无需在xe_vma里额外加成员省内存也省一次间接访问。对应的判定函数直接读 flags见 xe_vm.hstaticinlineboolxe_vma_read_only(structxe_vma*vma){returnvma-gpuva.flagsXE_VMA_READ_ONLY;}staticinlineboolxe_vma_is_null(structxe_vma*vma){returnvma-gpuva.flagsDRM_GPUVA_SPARSE;}// 直接复用核心层的 SPARSE 位staticinlineboolxe_vma_is_cpu_addr_mirror(structxe_vma*vma){returnvma-gpuva.flagsXE_VMA_SYSTEM_ALLOCATOR;}注意xe_vma_is_null()复用的是核心层的DRM_GPUVA_SPARSE而is_cpu_addr_mirror()用的是驱动私有的XE_VMA_SYSTEM_ALLOCATOR——一个映射的语义由核心位 用户位共同决定。6. VMA 的三种形态与再一层继承userptr通过组合上述 flagsXe 的xe_vma有四种互斥形态判定逻辑见 xe_vm.h形态判定背后存储BO 映射gem.obj ! NULL一个xe_boNULL / sparseDRM_GPUVA_SPARSE无读 0 写弃CPU 地址镜像XE_VMA_SYSTEM_ALLOCATORSVM 按需缺页userptr无 BO 且非 null 非镜像用户进程内存页staticinlineboolxe_vma_is_userptr(structxe_vma*vma){returnxe_vma_has_no_bo(vma)!xe_vma_is_null(vma)!xe_vma_is_cpu_addr_mirror(vma);}其中userptr又引入第二层继承——它在xe_vma之外再包一层xe_userptr_vma见 xe_vm_types.h 和 xe_vm.hstructxe_userptr_vma{structxe_vmavma;// ← 父structxe_userptruserptr;// 额外的 userptr 状态mmu notifier 等};staticinlinestructxe_userptr_vma*to_userptr_vma(structxe_vma*vma){xe_assert(xe_vma_vm(vma)-xe,xe_vma_is_userptr(vma));returncontainer_of(vma,structxe_userptr_vma,vma);// 又一次 container_of}于是形成一条三级继承链drm_gpuvaxe_vmadrm_gpuva gpuvaxe_userptr_vmaxe_vma vma\nxe_userptr userptr调用to_userptr_vma()前必须先用xe_vma_is_userptr()确认形态函数里有xe_assert兜底否则container_of会得到非法指针。7. 本篇小结机制作用代表符号结构内嵌首成员让 Xe 类型是一个 DRM 核心类型xe_vm.gpuvm/xe_vma.gpuvacontainer_of转型在核心层回调边界还原子类型gpuvm_to_vm/gpuva_to_vma/gpuva_op_to_vma_op字段访问器屏蔽父结构布局便于演进xe_vma_start/size/end/boUSERBITS复用私有 VMA 状态零额外内存XE_VMA_READ_ONLY…XE_VMA_SYSTEM_ALLOCATOR多级继承userptr 在 vma 上再扩展xe_userptr_vma/to_userptr_vma理解了这套继承 转型 flags 复用的骨架后续所有回调和 bind 流程读起来都会顺畅——每当核心层给你一个drm_*指针你就知道该用哪个container_of把它变回xe_*。关键源码位置速查主题文件关键符号三对结构定义drivers/gpu/drm/xe/xe_vm_types.hxe_vm/xe_vma/xe_vma_op转型 访问器drivers/gpu/drm/xe/xe_vm.hgpuva_to_vma/xe_vma_start…父结构定义include/drm/drm_gpuvm.hdrm_gpuva/drm_gpuva_flags私有 flagsdrivers/gpu/drm/xe/xe_vm_types.hXE_VMA_*L41–L52userptr 子类drivers/gpu/drm/xe/xe_vm_types.hxe_userptr_vma下一篇第 3 篇《VM 的创建与销毁》——xe_vm_create()如何一步步调用drm_gpuvm_init()DRM_GPUVM_RESV_PROTECTED与共享 resv 对象的意义根页表 / scratch page 的建立以及引用计数归零后vm_free回调与异步销毁 worker 的配合。

相关新闻

手把手教你掌握新一代AI工具(线上版)

手把手教你掌握新一代AI工具(线上版)

新手必看:手把手教你掌握新一代 AI 工具,快速提升生产力///“虾仔”>>>:jzit点top 在 2026 年的今天,AI 早已褪去“科技噱头”的标签,化作无数普通人桌面上的生产力引擎。然而,面对海量的 AI 产品…

2026/9/21 16:38:14 阅读更多 →
不要先问“用哪个 AI”,先盘点你的开发工作流

不要先问“用哪个 AI”,先盘点你的开发工作流

文章目录开篇本文不会讨论什么一、为什么不要一开始就问“用哪个 AI”二、一条完整开发工作流,通常包含哪些环节三、盘点工作流时,重点看这 5 个节点1. 需求到任务:你是不是经常边写边猜2. 阅读代码:你是不是总在找“入口到底在哪…

2026/9/15 17:16:22 阅读更多 →
Dism++系统优化指南:免费清理Windows垃圾的终极实战手册,三步腾出10GB磁盘空间

Dism++系统优化指南:免费清理Windows垃圾的终极实战手册,三步腾出10GB磁盘空间

Dism系统优化指南:免费清理Windows垃圾的终极实战手册,三步腾出10GB磁盘空间 【免费下载链接】Dism-Multi-language Dism Multi-language Support & BUG Report 项目地址: https://gitcode.com/gh_mirrors/di/Dism-Multi-language 周五晚&…

2026/9/21 8:25:57 阅读更多 →

最新新闻

OpenIM 架构与集成指南:基于 Go 的即时通讯服务端平台、OpenIMSDK 与 Webhook 扩展机制

OpenIM 架构与集成指南:基于 Go 的即时通讯服务端平台、OpenIMSDK 与 Webhook 扩展机制

即时通讯后端微服务WebSocket 【免费下载链接】open-im-server IM Chat OpenClaw 项目地址: https://gitcode.com/gh_mirrors/op/open-im-server 点击查看 免费下载 本文基于当前仓库中的希腊语版项目文档(docs/readme/README_el.md)整理而成…

2026/9/21 16:37:35 阅读更多 →
Handsontable 9.0 升级到 10.0 迁移指南:钩子重命名、HyperFormula 升级与默认值变更全解析

Handsontable 9.0 升级到 10.0 迁移指南:钩子重命名、HyperFormula 升级与默认值变更全解析

前端UI组件 【免费下载链接】handsontable JavaScript Data Grid / Data Table with a Spreadsheet Look & Feel. Works with React, Angular, and Vue. Supported by the Handsontable team ⚡ 项目地址: https://gitcode.com/gh_mirrors/ha/handsontable 点击…

2026/9/21 16:37:35 阅读更多 →
Caffeine 节点代码生成机制解析:从 Add* 生成器到 Node 类的完整链路

Caffeine 节点代码生成机制解析:从 Add* 生成器到 Node 类的完整链路

后端缓存抽象 【免费下载链接】caffeine A high performance caching library for Java 项目地址: https://gitcode.com/gh_mirrors/ca/caffeine 点击查看 免费下载 本指南聚焦 Caffeine(caffeine/)高性能缓存库中的代码生成体系&#xff1a…

2026/9/21 16:37:35 阅读更多 →
MicroPython 嵌入指南:在 C 应用中集成 MicroPython(embed port 实战)

MicroPython 嵌入指南:在 C 应用中集成 MicroPython(embed port 实战)

MicroPython 嵌入指南:在 C 应用中集成 MicroPython(embed port 实战) 【免费下载链接】micropython MicroPython - a lean and efficient Python implementation for microcontrollers and constrained systems 项目地址: https://gitcode…

2026/9/21 16:37:35 阅读更多 →
如何搭建自己的文件传输服务?一条Docker命令部署transfer.sh完整教程

如何搭建自己的文件传输服务?一条Docker命令部署transfer.sh完整教程

如何搭建自己的文件传输服务?一条Docker命令部署transfer.sh完整教程 【免费下载链接】transfer.sh Easy and fast file sharing from the command-line. 项目地址: https://gitcode.com/gh_mirrors/tr/transfer.sh transfer.sh 是一款用 Go 语言编写的轻量级…

2026/9/21 16:37:35 阅读更多 →
Handsontable 数据绑定实战指南:六大数据结构、数据装载 API 与空值语义全解析

Handsontable 数据绑定实战指南:六大数据结构、数据装载 API 与空值语义全解析

Handsontable 数据绑定实战指南:六大数据结构、数据装载 API 与空值语义全解析 【免费下载链接】handsontable JavaScript Data Grid / Data Table with a Spreadsheet Look & Feel. Works with React, Angular, and Vue. Supported by the Handsontable team ⚡…

2026/9/21 16:36:34 阅读更多 →

日新闻

agents-generator 决策矩阵全解析:从项目检测到 AGENTS.md 规则生成的 16 步判定流程

agents-generator 决策矩阵全解析:从项目检测到 AGENTS.md 规则生成的 16 步判定流程

agents-generator 决策矩阵全解析:从项目检测到 AGENTS.md 规则生成的 16 步判定流程 【免费下载链接】agentic-awesome-skills AAS Core is the local, agent-first control plane for complete catalog discovery, agent-owned selection, stack validation, and …

2026/9/21 0:00:01 阅读更多 →
gin-vue-admin 前端工具函数全景指南:src/utils 复用规范与源码级解析

gin-vue-admin 前端工具函数全景指南:src/utils 复用规范与源码级解析

gin-vue-admin 前端工具函数全景指南:src/utils 复用规范与源码级解析 【免费下载链接】gin-vue-admin 🚀ViteVue3Gin拥有AI辅助的基础开发平台,企业级业务AI开发解决方案,内置mcp辅助服务,内置skills管理,…

2026/9/21 0:00:01 阅读更多 →
Wox 全功能插件开发实战指南:基于 Python / Node.js 宿主与 WebSocket 的持久化插件体系

Wox 全功能插件开发实战指南:基于 Python / Node.js 宿主与 WebSocket 的持久化插件体系

桌面应用AI 应用插件系统 【免费下载链接】Wox A cross-platform launcher that simply works 项目地址: https://gitcode.com/gh_mirrors/wo/Wox 点击查看 免费下载 全功能插件(Full-featured Plugin)是 Wox 三类插件实现方式中能力最完整的…

2026/9/21 0:00:01 阅读更多 →

周新闻

Flutter for OpenHarmony游戏卡片渐变背景实战:从原理到性能优化

Flutter for OpenHarmony游戏卡片渐变背景实战:从原理到性能优化

直接铺开项目本身吧。这几个月我一直在折腾一件事:用Flutter给OpenHarmony做一款游戏集合类的App,说白了就是把若干小游戏塞进一个壳里,用统一入口分发。这个方向本身不算新鲜,真正让我花了不少心思的,是首页那堆游戏卡…

2026/9/21 3:13:20 阅读更多 →
Word表格编号全攻略:从列表编号到题注交叉引用

Word表格编号全攻略:从列表编号到题注交叉引用

写Word文档,最让人头疼的往往是那些“看起来不起眼”的小问题。比如表格编号这事:今天在表后面多加了两个空白行,明天给客户交稿前发现整个章节的编号全部错位,光是挨个改序号就能耗掉大半个下午。我前阵子帮人整理一份上百页的技…

2026/9/21 2:19:36 阅读更多 →
从第一个站到第二个站:独立开发者的静态网站选型与落地实践

从第一个站到第二个站:独立开发者的静态网站选型与落地实践

1. 项目概述1.1 核心需求解析做独立开发者这几年,说实话,第一个网站上线的那天晚上我兴奋得没睡着。但等它跑了半年,流量惨淡、功能臃肿、代码自己都懒得看第二遍之后,我才慢慢琢磨明白一个道理:第一个网站是练手&…

2026/9/21 4:51:05 阅读更多 →

月新闻

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

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

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

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

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

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

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

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

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

2026/9/19 23:35:34 阅读更多 →