本文将 DMA 重构为计算机体系结构中的“计算卸载”核心范式,深度剖析了从 PCIe 总线协议、IOMMU 虚拟化到 Linux 内核实现的底层机制,并揭示了该技术在“游戏安全攻防”“AI 算力加速”这两个极端场景下的双刃剑效应与关键作用。

DMA(Direct Memory Access,直接内存访问)是计算机体系结构中“性能解放”的基石技术

概述

DMA 不仅是“外设直接拷贝内存数据”的功能子集,而是早期并持续的“计算卸载(offloading)”范式——将数据传输的执行权、缓存一致性管理的部分责任以及(在某些实现中)协议处理的低阶控制从 CPU/内核迁移至可编程/专用的 I/O 设备或 DMA 引擎。

作为卸载技术的核心属性,DMA 引擎承担:请求发起(生成对等层 TLP/事务)、描述符队列管理(由驱动初始化)、对主机物理内存的直接访问(或通过 IOMMU 映射的 IOVA->PA 转换)、以及为高吞吐场景实现传输合并、重排或流水线化(Merge、Burst、Completion 合并等)。

类似于CPU 是老板,DMA 是物流总监。老板只需要签一张“发货单”(描述符),剩下的打包、分拣、甚至如果地址错了怎么处理,全由 DMA 自己搞定。DMA 为 CPU 减轻了负担(Offloading),让 CPU 去做更重要的决策,而不是把算力浪费在数据的搬运和协议处理上。

那么它是如何”发快递“的?

PCIe上的DMA:设备如何发起 Memory Read / Memory Write TLP

在 PCI Express 架构中,所有对系统内存的非CPU主导访问均通过Memory Read / Memory Write Transaction Layer Packets (TLPs) 在 Root Complex(RC)与端点(Endpoint)之间传递。

设备端 DMA 引擎(例如 NIC、NVMe 控制器、FPGA PCIe IP)通过以下流程实现主存读写:

  1. 驱动在主机侧通过配置设备的 BAR、设置描述符队列并写入门控寄存器(doorbell)
  2. 设备读取描述符后根据描述符内容生成对应的 Memory Read TLP(发起从主机内存读取)或 Memory Write TLP(把数据写入主机内存)。TLP 的格式包含事务类型、地址、长度、tag 等字段;当发起 Memory Read 时,设备发出 Read Request TLP 并随后接收 Read Completion (Cont.) TLPs
  3. 发起 Memory Write 则使用 Write TLP,通常随数据承载。

有关更高层次的流控(例如 Flow Control, Completion),以及合并/分段策略,见 PCI-SIG 规范

事务生成细节

  • 描述符与 DMA 引擎:设备的 DMA 引擎通常以“描述符/环/队列”为工作单元——驱动将目标 IOVA/PCI 地址与长度装入描述符链,设备按描述符顺序生成相应的 Memory TLP。该模型允许硬件实现多通道并发(channel interleaving)和 QoS。
  • Payload 尺寸与分段:设备需遵守主机侧的 MaxPayloadSize/MaxReadRequestSize,超出长度会被分段为多个 TLP。硬件可以合并小的描述以提高链路利用率(但受限于协议与主机能力)。
  • 顺序与原子性:PCIe 提供 Transaction Ordering Rules(例如 Posted Writes、Non-Posted Reads 的完成语义),设备必须以正确的 TLP ordering 保证系统一致性语义(特别在与 CPU 访问并行时需由软件/硬件协同提供 fencing)。

完成流(从TLP到主机内存)

当设备发起 Memory Read TLP,RC/Host 将在内存控制器处服务请求并通过 Completion TLP 将数据返回;对于 Memory Writes,TLP 到达主机后可直接写入主存(若存在 IOMMU,则写入前可能需要地址转换)。PCIe 的 Flow Control 与 Replay/FEC 机制(在 PCIe6.0/物理层的改进)影响了高带宽场景下 TLP 的传输效率和延迟,但不改变事务层的基本语义。

现代 DMA 是基于**包交换(Packet Switching)**的。设备和内存之间通过发送一个个小数据包(TLP)来交流。

通俗来说PCIe就像是一条高速公路,TLP(Transaction Layer Packet)就是公路上跑的快递货车,网卡(设备)想把数据存入内存 它不是把手伸进内存条 而是打包好一辆辆装满数据的”快递货车(Memory Write TLP)“然后开到内存控制器(Root Complex)那里卸货。

  • 描述符(Descriptor): 这是 CPU 给 DMA 留下的“任务清单”。比如:“去地址 A 拿 100 字节数据”。
  • 门铃(Doorbell): CPU 写好清单后,按一下门铃(写寄存器),告诉 DMA:“活来了,快干”。
  • 分段: 如果要运一整屋子的货,一辆车装不下。PCIe 规定每辆车(TLP)有最大载重(MaxPayloadSize),所以 DMA 会自动把大任务拆分成几十辆小车发出。

完成流:

  • 读数据(Memory Read): 网卡发个空车去内存(请求读),内存装满货后发个回程车(Completion TLP)给网卡。
  • 写数据(Memory Write): 网卡直接发满载的车去内存,通常不需要内存回执(类似平信),这样效率最高。IOMMU(以 Intel VT-d 为例):地址转换、页表遍历与 DMA 重映射(DMA Remapping)

IOMMU(以 Intel VT-d 为例)

地址转换、页表遍历与 DMA 重映射(DMA Remapping)

IOMMU(Input–Output Memory Management Unit 输入输出存储管理单元)在体系结构上承担IOVA(device view 的 DMA 虚拟地址)PA(系统物理地址)的转换、DMA 访问权限/域隔离(DMA 安全),以及支持设备对多虚拟机或多域的地址空间隔离(context entries / domain)。

在虚拟化场景下,IOMMU 是实现安全 DMA(防止设备越界写入)与设备直通(device passthrough)的关键硬件。

Intel VT-d 主要构建

Root Entry Table / Context Entry Table / Domain:VT-d 使用 Root Entry 指向设备的 Context Entry,后者包含域(Domain)ID 与转换根(根页表物理基地址)等;每个设备(或设备的 PCIe SR-IOV 虚拟功能)可被映射到特定 domain(即 IOVA 空间)。

DMA Remapping HW(DMAR):负责接收设备发起的 IOVA,并查找对应的转换(类似 CPU MMU 的多级页表)或触发页表遍历。

页表遍历(Page-Table Walk)流程 (简化)

  1. 设备发出 TLP 指向 IOVA(DMA 地址)。IOMMU 拦截该请求并将其当作需要转换的访问。
  2. 上一级索引查找(Context):IOMMU 使用设备标识(例如 PCIe Bus/Device/Function 或 PASID)在 Root/Context 表中找到对应 domain 与转换根(可视为类似 CR3 的页表基地址)。若未设置则产生错误或被拒绝。
  3. 多级页表查找:基于 domain 的转换根,IOMMU 读取多级页表项(类似 CPU 的多级页表)以把 IOVA 映射到最终物理帧(PA)。页表项包含权限、缓存/访问位以及可能的 PASID 信息。硬件可能支持大页(例如 2 MiB / 1 GiB)以减少查找深度。
  4. IOTLB(I/O Translation Lookaside Buffer)查询:在实际做完整的表遍历之前,IOMMU 首先查询 IOTLB(I/O-side TLB);命中则立即返回对应 PA;未命中则触发页表遍历/主存读取页表项并填充 IOTLB。IOTLB 的存在是为了解决页表遍历开销问题。
  5. 例外、错误处理与 PASID :
    • 缺页/权限异常:若页表项不存在或权限不足,IOMMU 可以向平台请求固件/驱动进行缺页处理或生成错误 Completion(由操作系统/管理程序处理)。VT-d 支持将异常报告到指定的系统端点。
    • PASID 支持:在多线程/多上下文设备(如支持多租户的 NIC)中,PASID(Process Address Space ID)允许多个进程/虚拟机在同一设备上并发使用 IOMMU 转换根。

我们可以看到 IOMMU在此的作用如同外设的”专属保安“与”翻译官“ 功能是如果设备看到的地址(IOVA)是假的,IOMMU 负责把它翻译成真的物理地址(PA),并防止设备乱访问。

外设(如网卡)拿着一个地址“房号 101”想进去,IOMMU(Input-Output MMU): 是坐在门口的保安兼前台,它查阅一本“入住登记表”(页表),发现“房号 101”其实对应的是大楼深处的“物理仓库 B区”。如果网卡想去“房号 999”(这是操作系统内核的私密房间),保安查表发现没权限,直接拦截(防止 DMA 攻击)。

页表遍历 (Page-Table Walk):保安(IOMMU)查表的过程。如果入住表很厚(多级页表),保安得翻好几页才能找到对应的物理房间号。这个过程比较慢,会消耗时间。

PASID (Process Address Space ID 进程地址空间ID):如果一张网卡同时服务于 10 个不同的程序(进程),怎么区分?PASID 就是给每个程序发的专属工牌。网卡发出的数据包带着工牌,IOMMU 就能知道这是属于哪个程序的,不会送错房间。

IOTLB 的作用、失效代价与加速策略

IOTLB 的功能:它是 IOMMU 的一级缓存,缓存 IOVA->PA 的转换以避免频繁的页表遍历。其命中率直接决定了 DMA 请求延迟与 CPU/内存带宽消耗(用于页表读取)的开销。对于多租户/多流量场景,高速网络/存储设备频繁生成大量小包的随机访问,会导致 IOTLB 压力并显著降低吞吐。

IOTLB 池化与共享策略:现代 IOMMU 实现可能提供 per-device 或 per-PASID 的 IOTLB 分区策略,以及硬件预取/合并条目以提升命中率。研究表明:在 100+ Gbps 级别的网络场景中,IOTLB miss 是关键瓶颈之一(“IOTLB wall”),需通过更大页、批量映射(hugepage-like mappings)、IOTLB 批量预填充或驱动/内核层面的批量 DMA mapping 策略来缓解。

IOTLB就是保安的”小抄“查表(页表遍历)太慢了,所以要用缓存(TLB)记下来。
如果刚才查过“房号 101”对应“仓库 B”,保安就记在小抄上。下次再来“房号 101”,直接放行,不用翻那本厚厚的登记表了。
如果来访的人太多,房间号各不相同,小抄记不下(Cache Miss),保安就得频繁翻大书,导致门口排长队。这就是高性能网络传输的瓶颈所在。

Linux 内核 DMA-API:抽象、一致性语义与驱动实践

Linux 的 DMA-API(dma_map_/dma_unmap_、dma_alloc_coherent、dma_mmap_attrs、streaming vs consistent mappings 等)为驱动屏蔽了底层系统在是否存在 IOMMU、缓存一致性模型、地址转换机制上的差异;驱动通过 API 把虚拟地址交给内核(或请求内核分配)并得到一组设备可见的 DMA 地址(IOVA),驱动随后把该 IOVA 告知设备以发起 TLP。

一致性(coherency)语义

  • Coherent vs Non-coherent Devices:若设备与 CPU 之间对同一缓存行的访问是 coherent(硬件支持缓存一致性),则 driver 可以减少显式的缓存 flush/invalidate 操作;否则驱动必须在dma_map/dma_unmap 阶段(或在提交/完成路径)显式做 cache flush 或 CPU 层面的同步(例如 dma_sync_single_for_cpu/dma_sync_single_for_device)。Linux DMA API 封装了这些操作,以在不同平台上保证语义一致性。
  • IO ordering / Fencing:DMA 操作的可见顺序依赖于设备、PCIe ordering rules 与平台缓存行为。通常需要显式 memory barriers(由驱动/内核发起)来保证在发布描述符与设备开始 DMA 之间的顺序。内核文档对何时需要 barrier 有明确建议。

与 IOMMU 的协同

在存在 IOMMU 时,dma_map_* 需要在 IOMMU 中建立相应的映射(或返回已经存在的 IOVA);驱动应使用 DMA API 而不是直接把虚拟地址传给设备,以避免跨体系结构的不兼容与安全问题。Linux 文档与驱动示例强调:驱动不能假设物理地址等于 DMA 地址(因为 IOMMU 可能翻译到不同 PA)

Linux操作系统为了屏蔽硬件差异,提供了一套标准接口

不同的 CPU(Intel vs ARM)和不同的主板构造不同。Linux 内核提供了一套统一的命令(API)。驱动只要喊“我要映射内存”,内核就会自动根据当前的硬件情况去操作 IOMMU 或刷缓存。

一致性(Conherency)问题:CPU 把数据改了,但还在自己的脑子里(L1 Cache),没写到纸上(内存)。这时候 DMA 如果直接从纸上读,就读到了旧数据。怎么做呢

  • Coherent Mapping: 相当于 CPU 每次改数据都强制写到纸上,或者硬件会自动同步,保证 DMA 看到的是最新的。
  • Streaming Mapping: 是一次性的。驱动告诉 CPU:“我要发快递了,把你脑子里的数据赶紧写到纸上(Flush)”,发完后再告诉 CPU:“快递发走了”。

零拷贝(Zero-copy)

零拷贝目标是消除在内核与用户态或设备与内存之间的多余内存拷贝(copy),以降低 CPU 占用并减少内存带宽消耗。在现代高速网络(10/25/40/100/200/400 Gbps)下,CPU 成本与内存带宽成为主要瓶颈,故需最大化 DMA 引擎与硬件队列来直接从/向用户缓冲区传输数据。

实现手段(系统层)

  • 零拷贝传输路径:常见路径为 NIC DMA 将接收到的数据直接写入用户空间缓冲区对应的物理页面(在内核中通过 pin / get_user_pages 或通过 IOMMU 建立直接映射),或通过内核直接映射(mmap)将设备 DMA 地址暴露到用户空间(并通过 PASID、IOMMU 来区分进程上下文)。
    这要求内核/驱动在 DMA-map 阶段完成 IOVA 映射并保持映射直到传输完成。
  • 避免缓存一致性开销:零拷贝常伴随 CPU 缓存线无效/回写开销;如果平台与设备不具备 DMA coherence,则驱动必须在设备写入后执行 invalidate(或在设备读取前执行 flush)。高性能方案倾向于使用设备/平台的硬件 coherent capability 或采用内存分配策略使数据走缓存一致的路径(例如使用 write-combined 或 non-cacheable 区域),但这可能影响 CPU 的访问延迟/吞吐。

IOMMU与零拷贝的性能与复杂度

IOMMU 在零拷贝场景中既是保证安全的必要组件(隔离不同进程/VM 的 DMA),又可能成为性能瓶颈:频繁为每一小包做个别 IOVA->PA 映射会导致 IOTLB 压垮与频繁的页表遍历,从而引入显著的延迟(见“ IOTLB wall”)。因此,实务中常见优化包括:预建立大页映射、批量映射/解除映射、使用设备支持的内存页共享/注册(registered memory)、以及 NIC/HW 支持的多页合并与队列化策略。

让数据直接从网卡飞到用户程序的内存里,不要在内核里倒腾。
传统模式下网卡 -> 也就是操作系统内核(复制一遍) -> 用户程序。这叫“中间商赚差价”,浪费 CPU。

零拷贝:网卡 -> 直接通过 DMA 写入 -> 用户程序的内存,需要 IOMMU 配合,精准地把用户程序的那块内存暴露给网卡,同时还要保证安全。

一致性、顺序与可编程卸载

可见顺序约束

DMA 与 CPU/设备之间的可见性语义由三个层面共同决定:PCIe 事务层 ordering/posted semantics、IOMMU/平台对缓存一致性的支持、以及驱动层的 memory barrier 策略。工程实践要求:在对描述符链、doorbell、或用户缓冲区状态做任何改变后,驱动必须在将工作提交给设备前调用正确的写屏障/flush(并在必要时确保 IOVA 映射已生效),以防设备基于陈旧描述发起访问。

卸载语义的正确性保证

当把协议处理(例如 TCP/IP 分片、校验、排序)卸载到 NIC 或 SmartNIC 时,设备不仅做数据搬运,还会改变数据语义(例如聚合多报文)。因此系统软件需就错误处理、事务回滚、以及安全隔离与设备固件协定接口;IOMMU/VT-d 提供内存层面的隔离,但协议层的可重入、重试与错误恢复仍需由设备/驱动共同设计。官方规范并不规定高阶协议卸载语义,故应由厂商文档与驱动实现细则明确。

既然是多核、多设备并行工作,必须规定好“谁先谁后”。

  • Ordering (顺序): 你不能在还没把信纸(数据)放进信封(内存)之前,就叫快递员(DMA)来取件。
  • Fencing (围栏/屏障): 代码里必须加一道“屏障”指令——“在屏障之前的数据没写完之前,绝对不允许按门铃通知 DMA”。
  • Offloading (卸载) 风险: 现在的智能网卡(SmartNIC)能帮忙处理 TCP 协议。但如果网卡算错了怎么办?驱动和网卡必须商量好一套“纠错暗号”。

DMA 重映射对虚拟化的影响(安全)

  • 设备直通(Passthrough):VT-d 允许 Hypervisor 把物理设备映射给 guest 并且通过 IOMMU 限制其只能访问 guest 的物理内存范围,从而无需 hypervisor 路径转发每个数据包(提高性能)。但必须正确配置根/上下文表以避免安全漏洞。
  • 多租户安全:IOMMU 提供 DMA 地址域隔离,阻止恶意设备或被攻破的虚拟机通过 DMA 写入其他 VM 的内存(DMA 攻击)。这一点在云环境中尤为关键。Intel/AMD 官方 VT-d / AMD-Vi 文档配置中断与错误上报机制以便在异常时采取强制隔离。

在云计算环境中,怎么让虚拟机用物理网卡,又怕它捣乱?

  • Device Passthrough (直通): 房东(Hypervisor)把某一个房间(物理网卡)的钥匙直接交给了租客(虚拟机)。

安全隐患: 租客有了钥匙,会不会趁机去开别的房间?

  • VT-d 的作用: IOMMU 会给这个租客划定一个圈(Domain),即使租客拿着真网卡发起了 DMA 请求,IOMMU 也会检查:“你只能访问属于你自己的那块内存”。如果越界,直接报警(报错)。

游戏安全领域

基于 DMA(直接内存访问) 的外挂被称为“硬件挂”或“双机挂”。它的核心逻辑正是利用了上文中深度剖析的 DMA 架构特性——“CPU 旁路(CPU Bypass)”

外挂代码不运行在游戏电脑上,而是运行在另一台电脑上,通过一块特制的 PCIe 硬件直接伸进游戏内存里“偷看”和“修改”数据。

物理架构:双机异构(2PC Setup)

为了躲避运行在游戏电脑(Host PC)上的反作弊系统(如 BattlEye, VAC, ACE),作弊者构建了一个物理隔离的系统整个过程完美对应了上节提到的 PCIe TLP 传输机制:

  • 受害者/游戏机 (Host PC): 运行游戏。上面不运行任何外挂软件,保持系统进程的“纯净”,让反作弊软件扫描不到异常。
  • 攻击者/雷达机 (Slave PC): 运行外挂逻辑(如透视绘制、自瞄计算)。
  • 特制 DMA 硬件 (FPGA): 通常是一块基于 Xilinx Artix-7 等芯片的 PCIe 开发板(如 Screamer, LeetDMA, RaptorDMA)。
    • 它插在游戏机的 PCIe 插槽上。
    • 通过 USB 数据线连接到雷达机
第一步:身份伪装 (Firmware Spoofing)
  • 原理: 当 DMA 硬件插入游戏机时,Windows 需要识别它。如果它报告自己是“Xilinx FPGA 开发板”,反作弊系统会立刻封号。
  • 操作: 攻击者会向 FPGA 刷入定制固件(Custom Firmware)
  • 伪装: 固件复制了真实硬件(如一张普通的 Realtek 网卡或 Wi-Fi 卡)的 PCIe Configuration Space(配置空间) 数据。
  • 结果: 游戏机的设备管理器和反作弊系统看到的是一张“合法的网卡”,而不是作弊卡。
第二步:建立物理内存镜像 (Scatter-Gather Read)
  • 雷达机发起指令: 外挂软件需要知道敌人在哪。它通过 USB 告诉 FPGA:“我要读游戏机内存的 0x10000000 地址”。
  • FPGA 发起 TLP:
    • FPGA 在游戏机的 PCIe 总线上发起一个 Memory Read TLP
    • 关键点: 这个请求直接发送给内存控制器(Root Complex)。
    • 旁路 CPU: 游戏机的 CPU(以及运行在上面的反作弊驱动)完全不知道发生了这次读取。没有 CPU 中断,没有 API 调用 hook,完全透明。
  • 获取数据: 内存控制器把数据打包成 Completion TLP 返回给 FPGA,FPGA 再通过 USB 传给雷达机。
  • 结果: 雷达机实时拥有了游戏内存的副本。
第三步:数据解析与透视 (ESP)
  • 雷达机计算: 外挂软件解析读取到的内存数据(如 Entity List,包含所有玩家的三维坐标 X,Y,Z)。
  • 绘制 (Overlay):
    • 方案 A(融合器): 雷达机生成透视画面,通过 HDMI 融合器(Fuser)叠加到游戏显示器上。
    • 方案 B(副屏): 直接在雷达机屏幕上显示 2D 雷达。
  • 安全性: 因为绘制过程不在游戏机显卡上进行,游戏机的截图/录屏功能截不到外挂画面(Stream proof)。
第四步:自瞄 (Aimbot) —— 写入与模拟

如果要实现自动瞄准,有两种路径:

  • 内存写入 (Memory Write TLP) —— 高危操作:
    • FPGA 直接发送 Write TLP 修改游戏内存中的“准星角度(ViewAngle)”。
    • 风险: 现代反作弊会检查内存完整性,或者发现准星移动极其不自然(瞬间跳变,扳机),容易被封。
  • 模拟鼠标 (KMBox / Arduino) —— 主流:
    • 流程: 雷达机计算出“枪口该往右移 10 像素”。
    • 硬件模拟: 雷达机通过串口指令控制一个硬件鼠标模拟器(如 KmBox)。
    • 输入: KmBox 插在游戏机的 USB 口上,伪装成一个普通的鼠标,向游戏机发送物理鼠标移动信号。
    • 优势: 看起来就像玩家手滑得很快,完全符合 USB HID 规范。

为什么这很难防御?

上文讲解的所有知识,我们可以看出 DMA 外挂的无解之处和“软肋”

1. 为什么难防?
  • 隐蔽性 (Stealth): 反作弊软件运行在 OS 内核。DMA 发生在 PCIe 总线和内存之间,是硬件层面的通信。操作系统无法监控 PCIe 总线上的每一个 TLP 包 除非有专门的硬件分析仪,但这不可能普及
  • 伪装性: 可以说只要固件写得好,它在软件层面看起来就是一张正常的声卡或网卡。
2. 防御手段(Cat and Mouse)
  • IOMMU / VT-d (面向游戏安全方向):
    • 原理: 也就是我们报告第三小节IOMMU提到的。如果在 BIOS 中开启 VT-d 并启用 Windows 的 VBS (Virtualization-based Security 虚拟化安全) / DMA Remapping
    • 效果: 操作系统会限制外设只能访问被授权的内存区域。如果“伪装网卡”试图读取游戏进程的内存(越界访问),IOMMU 会直接拦截请求并报错(Fault)。
    • 现状: 很多外挂教程第一步就是:“请进入 BIOS 关闭 VT-d/Virtualization”,或者攻击者寻找 IOMMU 的漏洞来绕过。
  • 配置空间扫描 (Heuristics):
    • 反作弊系统会深度扫描 PCIe 设备的配置空间(Config Space)。如果发现某张“网卡”的读写行为极其异常(例如一张声卡在疯狂读取内存,却没有任何声音数据输出),或者固件里的序列号是淘宝上买的“通用黑名单 ID”,就会封禁。
  • 物理层检测:
    • 这主要是局域网赛事(LAN Game)的防御手段。裁判直接检查电脑 PCIe 插槽有没有插奇怪的板子。

DMA 外挂的本质,是利用PCIe 总线“主控(Bus Master)”权限过大这一体系结构特点,这实际上是一场硬件架构设计软件安全审计之间的战争

FPGA 开发板的固件逆向工程

FPGA 固件逆向工程(FPGA Bitstream Reverse Engineering) 与传统的软件逆向(如 x86/ARM 汇编反编译)有着本质的区别,“固件”实际上是比特流(Bitstream),它不是指令序列,而是电路配置数据

逆向的目标是将这些 01 比特流还原为门级网表(Netlist),甚至进一步还原为 Verilog/VHDL 源码。

DMA与FPGA的关系?

FPGA 固件(Bitstream/Logic)与 DMA(Direct Memory Access,直接存储器访问)的关系可以概括为“大脑”与“搬运工”的关系,或者更准确地说是“控制逻辑”“数据传输机制”的关系。

FPGA作为主Master必须实现一个DMA引擎(DMA Engine)

一次典型的DMA传输

假设我们要用 FPGA 对电脑内存中的一张图片进行加速处理,固件与 DMA 的协作流程如下:

  • 驱动准备(Host):电脑驱动在内存中开辟缓冲区,放入图片数据,并建立一个描述符环(Descriptor Ring)
  • 门铃触发(Host -> FPGA):CPU 写 FPGA 的特定寄存器(Doorbell),通知固件:“有活干了”。
  • 获取任务(FPGA Firmware):FPGA 固件检测到 Doorbell,通过 PCIe 读取内存中的描述符。
  • 数据搬运(DMA Read):FPGA 固件根据描述符地址,发起 MRd (Memory Read) 请求。数据通过 PCIe 总线流入 FPGA 的 FIFO。
  • 流式处理(Processing):数据流经 FPGA 内部的算法模块(如卷积核)。
  • 结果回写(DMA Write):处理后的数据由固件发起 MWr (Memory Write) 请求,直接写入主机内存。
  • 中断通知(FPGA -> Host):固件发送 MSI-X 中断,告诉 CPU:“处理完了,去收货”。

FPGA 固件通过实现 DMA 引擎,打通了 FPGA 逻辑与计算机内存之间的高速数据"虫洞"

什么是FPGA逆向?
比特流(Bitstream)的本质

在软件中,二进制是 CPU 执行的指令;而在 FPGA 中,比特流是对底层硬件资源的配置。它控制了:

  • LUT (Look-Up Table) 的真值表内容(决定逻辑功能)。
  • MUX (Multiplexer) 的选择位(决定信号路由路径)。
  • Flip-Flop 的初始化状态和复位属性。
  • PIP (Programmable Interconnect Point) 的开关状态(决定线与线是否连接)。
逆向的层次
  • 格式解析(Format Parsing):剥离文件头、校验和(CRC)、命令字,提取纯净的配置数据。
  • 映射还原(Mapping Recovery):知道“比特流中的第N位"对应"物理坐标(X , Y)的某个PIP开关”。这是最难的一步。
  • 网表重建(Netlist Reconstruction):将物理配置转换为逻辑网表(Gate-level Netlist)。
  • 行为分析(Behavioral Analysis):从网表中识别状态机、计数器、加密算法核等高层逻辑。
如何破解"黑盒"格式

由于 Xilinx、Intel (Altera) 等厂商不公开比特流格式,逆向的核心方法论是相关性分析(Correlation Analysis),也就是俗称的“比特流模糊测试(Bitstream Fuzzing)

差分分析法(Differential Analysis)

这是最主流的逆向手段,由 Note 和 Rannaud 在 2008 年提出,并在 Project X-Ray 中被发扬光大。

算法流程

  • 基准设计:编写一个最简单的 Verilog 设计(例如,仅实例化一个 LUT)。
  • 微小变异:修改设计中的一个参数(例如,将 LUT 的初值从 0001 改为 0010),保持位置约束(Location Constraint)不变。
  • 编译生成:使用厂商工具(Vivado/Quartus)生成两个比特流 B1和B2。
  • 异或对比:计算Diff = B1 ⊕ B2
  • 定位:Diff中为 1 的位,就是控制该参数的配置位。
Python 实现:简单的比特流差异定位
import numpy as np

def load_bitstream(filename):
    # 简化示例:读取二进制并转为 numpy 数组
    with open(filename, 'rb') as f:
        data = np.frombuffer(f.read(), dtype=np.uint8)
    return np.unpackbits(data)

def find_controlling_bits(file1, file2):
    bits1 = load_bitstream(file1)
    bits2 = load_bitstream(file2)

    # 寻找差异
    diff = np.bitwise_xor(bits1, bits2)
    indices = np.where(diff == 1)[0]

    print(f"Found {len(indices)} differing bits.")
    print(f"Bit indices: {indices}")
    # 在真实工程中,需要将这些 indices 映射回 Frame 地址和 Byte 偏移
    return indices

# 假设我们有两个比特流,唯一的区别是一个 LUT 的 INIT 值不同
# find_controlling_bits("design_A.bit", "design_B.bit")

比特流结构与解密
Xilinx 7 Series 比特流结构

一个典型的 .bit 文件包含:

  • Sync Word0xAA995566,用于告诉 FPGA 配置逻辑“数据开始了”。
  • Packet Headers:类型 1 和类型 2 数据包,包含操作码(OPCODE),如写配置寄存器(FDRI)。
  • Frame Data:这是核心。Xilinx 芯片被划分为多个 Tile(CLB, DSP, BRAM),每个 Tile 对应比特流中的若干 Frame。
加密与侧信道攻击

高端 FPGA 固件通常使用 AES-256 加密(CBC 或 GCM 模式)。密钥存储在芯片的 eFuse 或电池供电的 BBRAM 中。

如何提取密钥?

  • 差分功耗分析(DPA):在 FPGA 解密启动时,通过监测电源线的微小电压波动,分析 AES S-Box 操作时的功耗特征来恢复密钥。
  • Starbleed 漏洞 (CVE-2020-10935):针对 Xilinx 7 系列。如果你能物理访问配置接口,即使比特流是加密的,通过操作 WBSTAR 寄存器,可以让 FPGA 将解密后的内部配置数据“吐”回到配置接口,从而实现解密后的比特流回读
逆向工程的典型应用
  • 硬件木马检测 (Hardware Trojan Detection):攻击者可能在供应链中修改比特流,植入木马(例如,当计数器达到特定值时触发后门)。
    实现:逆向比特流得到网表 -> 与原始设计的 Golden Model 进行形式化验证(Equivalence Checking)-> 发现多余的逻辑门。
  • IP 核盗版取证:某公司怀疑竞争对手抄袭了自己的专有算法 IP。
    实现:提取对手产品的 Flash 内容 -> 逆向比特流 -> 识别出 DSP Slice 的连接方式和系数 -> 证明其数学结构与自家 IP 一致。
  • 跨厂商迁移:在某些极端情况下(如旧芯片停产),需要理解旧系统的逻辑以移植到新 FPGA 上,且源码已丢失。

人工智能领域

在人工智能(AI)领域,DMA 同样被广泛应用,但它通常不叫简单的 DMA,而被称为 Tensor DMAAsync Data MoverRDMA (Remote DMA)

AI 的“内存墙(Memory Wall)”问题

AI 计算(特别是深度学习)的本质是矩阵乘法(GEMM)。现代 GPU/NPU 的计算单元(Tensor Core)算力极强,但瓶颈在于数据搬运。计算单元算得太快,数据(权重和激活值)还在内存(HBM/DRAM)里没取出来。计算单元被迫闲置(Stall),这是巨大的算力浪费。DMA 在这里负责“喂饭”。它的目标是实现 Compute-Memory Overlap(计算与通信的掩盖/重叠)——即在计算当前数据的同时,DMA 已经在后台把下一批数据搬到了片上缓存(SRAM)中。

应用场景与实现思路

我们将 AI 中的 DMA 应用分为芯片内部(微观)集群之间(宏观)两个维度。

1. 芯片内部:Tensor DMA 与双缓冲(Double Buffering)

这是 NPU(如 Google TPU、华为 Ascend、NVIDIA Tensor Core)架构设计的核心。

  • 实现思路:
    传统的 DMA 只能搬运连续地址。但 AI 数据(张量)通常是多维数组,物理地址可能是不连续的(Strided Access)。
    因此,AI 芯片设计了 2D/3D DMA 引擎,支持复杂的地址跨步(Stride)搬运矩阵转置
  • 具体流程(流水线化):
    • Buffer A 计算中: 矩阵乘法单元(MXU)正在全力计算 SRAM Buffer A 中的数据。
    • Buffer B 搬运中(DMA): 与此同时,DMA 引擎完全不占用计算资源,正在从 HBM(高带宽内存)中预读取下一批数据写入 SRAM Buffer B。
    • 切换: 计算完成后,MXU 立即切换到 Buffer B 计算,DMA 转头去填充 Buffer A。

权威案例:

Google TPU v1 Paper: 在 ISCA 2017 发表的论文:
In-Datacenter Performance Analysis of a Tensor Processing Unit》—— 数据中心内张量处理单元的性能分析

Many architects believe that major improvements in cost-energy-performance must now come from domain-specific hardware. This paper evaluates a custom ASIC---called a Tensor Processing Unit (TPU)---deployed in datacenters since 2015 that accelerates the inference phase of neural networks (NN). The heart of the TPU is a 65,536 8-bit MAC matrix multiply unit that offers a peak throughput of 92 TeraOps/second (TOPS) and a large (28 MiB) software-managed on-chip memory. The TPU's deterministic execution model is a better match to the 99th-percentile response-time requirement of our NN applications than are the time-varying optimizations of CPUs and GPUs (caches, out-of-order execution, multithreading, multiprocessing, prefetching, ...) that help average throughput more than guaranteed latency. The lack of such features helps explain why, despite having myriad MACs and a big memory, the TPU is relatively small and low power. We compare the TPU to a server-class Intel Haswell CPU and an Nvidia K80 GPU, which are contemporaries deployed in the same datacenters. Our workload, written in the high-level TensorFlow framework, uses production NN applications (MLPs, CNNs, and LSTMs) that represent 95% of our datacenters' NN inference demand. Despite low utilization for some applications, the TPU is on average about 15X - 30X faster than its contemporary GPU or CPU, with TOPS/Watt about 30X - 80X higher. Moreover, using the GPU's GDDR5 memory in the TPU would triple achieved TOPS and raise TOPS/Watt to nearly 70X the GPU and 200X the CPU.

许多架构师认为,成本、能效和性能的重大提升现在必须来自领域特定的硬件。本文评估了自2015年以来部署于数据中心的定制ASIC设备---称为张量处理单元(TPU)---加速神经网络(NN)推理阶段。TPU的核心是一个65,536个8位MAC矩阵乘法单元,峰值吞吐量为92 TeraOps/秒(TOPS),并配备一个大型(28 MiB)软件管理的片上存储器。TPU的确定性执行模型比CPU和GPU时变优化(缓存、乱序执行、多线程、多处理、预取等)更符合我们神经网络应用第99百分位的响应时间要求,这些优化帮助平均吞吐量超过保证延迟。缺乏这些功能有助于解释为什么尽管拥有众多MAC和大内存,TPU体积相对较小且功耗较低。我们将TPU与服务器级Intel Haswell CPU和Nvidia K80 GPU进行了比较,这两者是同期部署在同一数据中心的处理器。我们的工作负载采用高级TensorFlow框架编写,使用生产型神经网络应用(MLP、CNN和LSTMs),这些应用占我们数据中心神经网络推断需求的95%。尽管某些应用使用率较低,TPU的平均速度约为同期GPU或CPU的15到30倍,而TOPS/瓦数则高出约30到80倍。此外,在TPU中使用GPU的GDDR5内存,将实现三倍的TOPS性能,使TOPS/瓦数提升至GPU近70倍,CPU提升200倍。

该论文明确描述了 DMA Controller 如何将权重从 DRAM 搬运到 Unified Buffer(SRAM)中,供给 Systolic Array(脉动阵列)使用。在这里,DMA 被设计为特殊的指令 CISC 指令,专门负责 Matrix(矩阵) 加载。

2. 宏观集群:RDMA 与集合通信(Collective Communication)

这是大模型分布式训练(Distributed Training)的基石。

  • 现状: 训练一个大模型需要上千张 GPU 协同。
  • 问题: GPU A 计算完一部分梯度,需要传给 GPU B。如果走 GPU -> CPU内存 -> TCP/IP协议栈 -> 网卡 -> 网线 这条老路,延迟太高,CPU 会累死。
  • 解决方案:RDMA (Infiniband / RoCE) 配合 GPUDirect
  • 具体思路(Zero-copy 网络):
    • GPUDirect RDMA: 网卡(NIC)直接通过 PCIe 总线访问 GPU 的显存(HBM)
    • 绕过 CPU: 数据直接从 GPU A 的显存搬到网卡,通过光纤传到对面网卡,再直接写入 GPU B 的显存。
    • 全自动: CPU 仅负责建立连接,之后的数据洪流完全由 DMA 引擎在网卡和 GPU 之间自动流转。
3. 数据加载:GDS (GPUDirect Storage)
  • 场景: AI 训练需要从硬盘读取海量的图片或文本数据。
  • 传统路径: SSD -> 系统内存 -> CPU 复制 -> GPU 显存。
  • DMA 创新: NVMe over PCIe P2P DMA。思路是 GPU 的 DMA 引擎直接向 NVMe SSD 发起读取请求,数据从 SSD 直接通过 PCIe 总线流向 GPU 显存,完全不经过系统主内存(System RAM)。

Transformer 架构中,DMA 引擎需要处理极其复杂的依赖关系(Dependency Graph),硬件层面实现了细粒度的同步机制(Semaphore/Barrier),让计算和搬运的流水线严丝合缝。

参考文献与致谢

致谢:

本文的研究离不开多个权威标准化组织、芯片厂商技术文档以及顶级计算机体系结构会议(ISCA, OSDI)的支持。

需要注意的是,在本文《异构计算的数据动脉:DMA 的架构演进、底层机制与跨域应用解析》中,仍有多项具体的工程实现细节未能详尽提及(例如不同操作系统内核版本对 IOMMU 分配策略的细微差异,以及 CXL 等下一代互联协议对 DMA 的重构等)。此外 因文中部分参考文献版权原因故无法附带直接访问链接。

参考文献:

[1.] PCI Express Base Specification》(PCI Express 基础规范 / PCI-SIG 官方文档)
[2.] Intel Virtualization Technology for Directed I/O (VT-d) Architecture Specification》(Intel 定向 I/O 虚拟化技术架构规范)
[3.]Dynamic DMA Mapping using the Generic Device》(使用通用设备的动态 DMA 映射 / Linux 内核文档)
[4.] In-Datacenter Performance Analysis of a Tensor Processing Unit》(数据中心内张量处理单元的性能分析 / Google TPU v1 论文)
[5.]NVIDIA GPUDirect RDMA Technology Overview》(NVIDIA GPUDirect RDMA 技术概览)
[6.] Thunderclap: Exploring Vulnerabilities in Operating System IOMMU Protection via DMA from Untrustworthy Peripherals》(Thunderclap: 通过不可信外设的 DMA 探索操作系统 IOMMU 保护中的漏洞)
[7.]PCILeech: Direct Memory Access Attack Hardware》(PCILeech: 直接内存访问攻击硬件 / 早期 DMA 攻击研究)
[8.] 《Understanding the Linux Kernel》(深入理解 Linux 内核 / 第 3 版)
[9.] Muli Ben-Yehuda, et al. Utilizing IOMMUs for Virtualization in Linux and Xen. OLS, 2006.
[10.] Nadav Amit, Muli Ben-Yehuda. The IOMMU: Your PC's Sieve. arXiv:1004.1866, 2010. (关于 IOMMU 安全性的早期研究)
[11.]AMBA AXI and ACE Protocol Specification》(AMBA AXI 与 ACE 总线协议规范 / ARM 架构 DMA 基础)
[12.] Remote Direct Memory Access: An efficient and scalable communication mechanism》(远程直接内存访问: 一种高效且可扩展的通信机制)
[13.] BattlEye: The Anti-Cheat Gold Standard (BattlEye官网: 反作弊的黄金标准 / 关于内核级保护的机制描述)

[14.] Anti-Cheat-Expert ACE (ACE 腾讯游戏安全: 外挂特征提取、行为分析、原理分析等,辅助制定对抗策略)

[15.] Project X-Ray (Xilinx 7-Series Documentation) 关于Xilinx 7系列比特流格式的文档。

Logo

DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。

更多推荐