尧图网络科技YAOTU DIGITAL 获取报价
获取报价
首页 / 资讯中心 / 文章详情

TDISP从入门到落地:PCIe接口安全状态机与TLP过滤规则详解

发布时间:2026/9/26 2:27:41

资讯中心
01
ARTICLE

TDISP从入门到落地:PCIe接口安全状态机与TLP过滤规则详解

TDISP从入门到落地:PCIe接口安全状态机与TLP过滤规则详解
做FPGA PCIe加速卡的兄弟应该都遇到过这个场景客户要求做机密计算环境下的设备隔离硬件上支持了但问到设备如何证明自己可信DMA地址如何限制哪些TLP在锁定后要拦掉你会发现手里只有零散的规范概念——SPDM、IDE、TDISP它们好像一环扣一环但谁也说不清全貌。我在整理PCIe协议学习笔记时TDISP正好是卡了很久的一块。这篇是TDISP系列的第一篇重点把Overview讲透然后把TLP Rules的骨架搭起来。后续再展开状态机的每条转换路径、IDE封装细节和DIFDevice Interface Fabric的软件视图。我不会贴整段规范条文那样等于翻译文档。按照真正啃协议的人的习惯来先说这个协议解决什么问题再说它凭什么能解决最后落到TLP这一层把锁定之后哪些报文能走、哪些必须拦这条主线捋直。读完你应该能回答三个问题TDISP在整个PCIe安全体系里的位置是什么接口安全状态机到底在管什么TLP规则的本质约束是什么1. TDISP到底在解决什么问题一个来自云环境的安全威胁模型先想一个再常见不过的场景一台物理服务器上跑着多个虚拟机其中一个机密虚拟机被分配了一块加速卡或NVMe盘。从系统软件的角度看CPU侧的内存有加密和隔离机制页表有权限控制VMM也不是那么可信。但PCIe设备呢设备发起DMA读写的方向是绕过CPU的它可以直接访问内存里的任意地址也可以发起恶意的中断注入。传统的IOMMU可以在一定程度上限制地址范围但IOMMU本身是软件可配置的而且它拦不住设备自己就是恶意实体这种情形——设备固件被篡改、设备被物理攻击、设备发起不符合协议规范的行为这些都超出IOMMU的能力边界。TDISP的全称是TEE Device Interface Security Protocol它属于PCIe规范里从6.x开始逐渐成形的一整套机密计算支撑机制。它的目标非常具体在设备与一个受信任的执行环境TEE之间建立可验证的安全关系然后通过一套接口状态机和TLP过滤规则把设备约束到只能做你允许它做的事这一状态。我最初看到TDISP时有个误解以为它是对PCIe链路做加密的协议——那是IDEIntegrity and Data Encryption的活。TDISP更像是一个策略执行层它决定某个设备接口在什么状态下允许哪些TLP通过而IDE负责在链路和传输层给这些TLP加上完整性和机密性保护。两者配合才能构造一条从TEE到设备功能端的可信通路。用保安系统来类比SPDM是验身份证的证明设备确实是它声称的那个设备IDE是给车辆加物理防护的保证运输途中不被换货或偷看TDISP则是门禁规则——几点开门、什么车能进、进去能停哪个车位全都提前定好。没有TDISP前面两步做完仍然留着一个大洞设备一旦被攻破它可以随意发起DMA、乱发中断系统侧没有一道开关能把它立刻约束住。这正是TDISP被设计出来的核心动机。顺着这个逻辑往下走你就能理解为什么TDISP规范里充斥着接口安全状态TLP拦截UNDER_FIRE这类词。它本质上是一个分层的安全状态框架先认证再建会话再锁定锁定之后一切越界行为都被硬件拦截并且把违规事件变成可上报的状态。设备侧的DIF逻辑把这个框架实现为具体的状态机软件侧的TEE驱动通过MMIO寄存器和消息请求与DIF通信。这种软件配置一次硬件持续强制执行的设计避免了每次I/O操作都要陷入软件的情况性能代价可控。2. 核心概念拆解DIF、Interface、Selector和TDISP命令的协作关系在TDISP的规范里几个术语容易混淆我先把它们理清楚。首先是Interface接口它指的是设备暴露给系统的一个功能接口。对普通PCIe设备来说一个物理功能PF或虚拟功能VF就是一个Interface但如果设备有多个PF且各自独立那么每个PF都被视作独立的Interface来管理。这个粒度很重要因为TDISP的安全状态是针对每个Interface单独维护的不是整个设备统一一个状态。DIFDevice Interface Fabric是设备内部负责执行TDISP逻辑的实体。它不是什么新硬件更像是一段固化在设备固件或RTL里的状态机模块。DIF与系统侧的TEE驱动之间通过消息交互消息的载体是标准PCIe配置写请求或MMIO写操作。规范里定义了一组命令比如INTERFACE_SECURITY_COMMAND、TOGGLE_DEVICE、GET_INTERFACE_STATE等。每个Interface在DIF里都有对应的安全状态这些状态从未配置到锁定逐级推进。Selector这个概念也经常被提起。Selector是软件侧用于标识某个DIF或接口的编号。在消息交互时TEE驱动通过Selector告诉目标设备我要操作的是哪一个安全实例。对应到PCIe层面Selector通常关联到设备的BDFBus/Device/Function号或Request ID。我在实现阶段遇到的一个细节是同一个物理设备如果被两个不同的TEE上下文分配那么Selector和Interface的映射关系必须由设备固件维护好不能出现两个TEE同时锁定同一个接口的情况。规范对此有约束但落到实现时仍需要仔细设计地址映射和仲裁逻辑。下面这张表总结了TDISP涉及的核心对象和它们在系统中的角色方便对照理解对象含义物理形态主要作用Interface设备暴露的功能接口PF/VF或独立物理功能作为安全状态的最小管理单元DIF设备接口安全结构设备内部状态机模块执行TDISP消息处理、维护接口安全状态Selector接口的软件可见标识整型编号消息寻址关联TEE上下文与接口TEE驱动运行在受信任环境中的软件虚拟机驱动或固件发送TDISP配置命令管理安全会话IDE完整性与数据加密引擎链路层或传输层加密模块保护TLP不被篡改和窃听那TDISP命令具体怎么走我以最常见的将一个接口从初始状态推进到锁定状态的流程为例说明。系统侧的TEE驱动先通过SPDM完成设备认证这个过程会拿到设备的能力描述、证书链等然后向DIF发送SET_INTERFACE_SECURITY_STATE之类的命令把目标接口从TDISP_UNCONFIGURED推到TDISP_CONFIGURING。接下来TEE驱动会配置IDE流、DMA地址范围、中断向量等资源再发命令让接口进入TDISP_CONFIGURED。最后一步是发送LOCK命令接口进入TDISP_LOCKED此时TLP过滤规则正式生效。这一条链路里的每一步都有对应的状态检查任何一步不满足或命令参数非法DIF都会拒绝转换并返回错误码。这里有个需要强调的为什么为什么TDISP不直接在设备上电后就锁定而要费这么大劲走一套状态推进流程因为设备上电之初驱动还不知道设备的能力和配置空间内容贸然锁定会把配置过程本身也锁死。TDISP的推进流程本质上给了软件一个配置窗口在窗口内允许正常的PCIe配置访问和初始化窗口关闭LOCK之后就进入强制执行阶段。这种分阶段推进的设计保证了设备初始化的灵活性和运行期的安全性两者不是二选一。3. 接口安全状态机全景从UNCONFIGURED到UNDER_FIRE的完整路径TDISP状态机是整个协议的骨架。我按实际阅读规范的顺序把每个状态讲清楚同时标注是什么操作能推进状态、进到每个状态后系统的行为预期是什么。3.1 五个核心状态各自的职责边界规范定义了多个接口安全状态我先挑五个主状态展开。TDISP_UNCONFIGURED是出厂默认状态。设备完成常规PCIe枚举后所有接口都处于这个状态。此时没有任何TDISP安全上下文TLP过滤规则不生效设备对普通驱动来说就是一个标准PCIe设备。也就是说即便不启用TDISP设备也能正常工作——这是向后兼容的基础。TDISP_CONFIGURING表示正在配置安全上下文。处于这个状态时TEE驱动可以写入DMA范围、IDE参数、中断策略等配置。规范允许在这个状态下进行地址映射相关的操作但尚未要求硬件强制过滤。这个窗口期的存在是为了让软件有空间准备资源。TDISP_CONFIGURED表示上下文已经配置完毕等待锁定。状态名里的Configured可能会让人误以为规则已经生效实际上在这个状态设备仍然可以先执行部分非阻塞性的TLP真正强约束要到LOCK之后。规范对CONFIGURED和LOCKED的关键区别在于CONFIGURED状态允许软件继续做补充配置LOCKED之后配置通道基本关闭。TDISP_LOCKED是运行态的核心状态。接口进入LOCKED后TDISP定义的TLP规则全部生效不符合策略的MMIO访问、DMA越界、中断越权等行为会被硬件拦截部分情况会触发错误上报。这是锁定即强制的语义所在。TDISP_UNDER_FIRE是安全响应状态。当设备检测到违规行为比如IDE完整性校验失败、非法TLP被截获、配置命令被篡改后DIF会主动将接口置入这个状态。进入UNDER_FIRE后设备通常会中止当前的数据通路部分实现会选择彻底阻断该接口的所有后续TLP直到软件显式执行恢复操作。3.2 状态转换的触发条件与软件操作示例状态的迁移由两类因素触发一类是TEE驱动主动发送的命令另一类是设备内部检测到的事件。以下表列出主要路径当前状态触发条件/命令下一状态说明UNCONFIGUREDSECURE_CREATE会话成功CONFIGURING认证完成开始配置资源CONFIGURING配置参数写入完成CONFIGUREDDIF确认所有配置合法CONFIGURED收到LOCK命令且校验通过LOCKED进入强制过滤模式LOCKED检测到安全违规事件UNDER_FIRE硬件主动降级阻断I/OUNDER_FIRE软件执行RECOVER命令并验证LOCKED设备恢复正常运行我之前阅读规范时容易忽略的一个点从一个状态到另一个状态并不只是发命令这么简单。DIF在每一个转换点都要做参数校验。比如从CONFIGURING到CONFIGURED必须确保DMA范围描述符合法、IDE流已经被正确设置、中断向量索引在设备支持范围之类。任何一项校验不通过DIF会回复错误状态并停留在原状态而不会静默失败。3.3 接口状态独立性与多功能设备的处理一个设备有多个接口时TDISP允许每个接口处于不同状态。比如说一块双端口网卡PF0给一个常规虚拟机使用可以一直保持在UNCONFIGUREDPF1给机密虚拟机使用可以推进到LOCKED。这种独立性对实际部署非常关键因为它允许同一块物理设备同时服务普通负载和机密负载不会因为一个接口的安全策略而影响整卡。但这种独立性也带来了实现层面的复杂度DIF内部需要为每个接口维护独立的状态寄存器和过滤规则并且要注意接口间是否存在共享资源。如果两个接口共享同一个DMA引擎那么一个接口LOCKED后发起DMA时硬件必须判断它是否落入该接口允许的地址范围内而不是简单按整个设备的范围来过滤。这个逻辑在软件规格里看不太出来但在RTL实现里会成为一个很典型的设计难点——我当时在设计DMA过滤时就因为共享引擎吃了亏最后改成按Request ID区分过滤策略才解决问题。4. TLP规则详解LOCKED状态下哪些报文能走、哪些必须拦TDISP的TLP规则是它和IDE最大的区别点——IDE只管加密和完整性TDISP还要管这个报文合不合规。进入LOCKED状态之后DIF会对经过该接口的每一个TLP做策略判定。下面把规则按类别拆开讲。4.1 TLP分类回顾先认清每种报文是干什么的PCIe事务层Transaction Layer的TLP按类型可以粗分为四类Memory请求读/写、Configuration请求读/写、I/O请求、Message请求包括INTx中断、PME、ERR等。此外还有Completion完成报文用于响应前面的请求。TDISP的规则不是一刀切禁止某一类而是按类型结合地址、请求者、方向来做组合判定。4.2 配置请求与错误上报的约束接口LOCKED后常规的Configuration读写请求基本被拦截。原因很直接配置空间里包含BAR、MSI-X表、控制状态寄存器如果运行期还能被任意软件改写配置空间那么前面建立的DMA地址限制和中断策略就形同虚设。因此规则规定LOCKED状态下只有与TDISP管理相关的特定MMIO访问比如DIF的消息接口允许通过其他配置写请求会被直接丢弃配置读请求返回全F或错误完成。这里有个细节值得注意设备自身或驱动主动上报错误怎么办PCIe的错误上报通常走ERR_*消息。TDISP规则允许适当的错误上报消息继续传递因为安全机制需要把违规通知到系统管理侧。但同时禁止设备通过错误消息注入虚假中断来干扰其他功能。我在做测试时就碰到过一种情况DIF拦截了一个非法DMA写请求之后设备按PCIe规则发出一个URUnsupported RequestCompletion结果这个Completion本身也被误拦导致驱动侧看到的是一个超时而不是明确的错误码。后来在过滤逻辑里专门给错误Completion加了旁路通道才解决。4.3 DMA地址范围约束DMRS的角色DMA是TDISP要控制的最核心的路径。规范里通过设备内存范围集DMRSDevice Memory Range Set来限定DMA读写能访问哪些主机物理地址。说白了就是给每个Interface配一张白名单只有落在白名单里的地址才允许DMA其他地址一律拒绝。这个机制比传统IOMMU更进一步IOMMU是系统侧的页级隔离TDISP则要求设备侧自身具备地址校验能力防止设备被攻破后绕过IOMMU。以写入请求为例DIF需要检查TLP头里的地址字段是否落在该接口允许的写地址范围内。若落在范围内且Request ID匹配该接口的标识就放行否则丢弃或走错误路径。对于读请求同理还要额外考虑完成报文Completion with Data的返回路径。等待数据返回时设备必须记录这次读请求的上下文确保完成报文返回时也能校验其对应的地址和标签没有越界。这一对请求-完成的闭环校验是我认为TDISP实现中容易漏掉的地方——很多初做过滤逻辑的人只查了请求方向没查Completion方向结果出现越界读却被正常返回数据的漏洞。4.4 中断TLP的细分控制MSI-X向量级隔离中断是另一个重点。TDISP不满足于允许或禁止该接口发中断而是把粒度细化到MSI-X的每一个向量。LOCKED状态下接口只能通过被TEE驱动预先配置的向量发起中断其他向量即便触发也会被拦截。这样做的目的是防止恶意设备通过中断向量注入伪造事件干扰机密虚拟机内的逻辑。从实现角度看设备需要维护一张允许向量表在配置阶段由TEE驱动写入DIF。硬件在生成中断时把中断对应的向量索引与允许表比对。比对不通过则丢弃并触发UNDER_FIRE或安全日志。这个过程的性能开销很小因为通常只是几次查表操作。但要注意中断的过滤不能误伤正常的中断合并MSI-X支持多向量合并配置允许表时需要把一组相关向量都纳入而不能只开一个。4.5 TLP规则的强制执行可以有多严格规范没有规定死所有过滤逻辑的具体实现它给出的是策略框架具体严格程度允许设备厂商自行定义。有的设备选择只拦最明显的越权访问有的设备选择做全量TLP深度校验——后者安全性更高但逻辑面积和功耗也更高。对FPGA实现而言我建议分两个等级来设计第一级是粗粒度过滤器按类型地址范围快速判决占资源少、能挡住绝大多数恶意行为第二级是细粒度校验对Completion和中断向量做精确匹配只在关键路径上启用。这样既能满足TDISP的安全语义又不会让时序收敛变成灾难。下面这张表是我在设计过滤逻辑时归纳的规则要点可以直接作为实现参考TLP类别LOCKED状态下的默认策略补充条件Configuration Write禁止TDISP管理消息接口除外Configuration Read允许有限访问返回受限数据具体允许范围由设备实现决定Memory WriteDMA仅允许写入DMRS白名单地址Request ID匹配接口标识Memory ReadDMA仅允许读取DMRS白名单地址Completion返回同样校验地址MSI-X中断向量仅允许预配置向量通过向量索引查表错误上报Message允许有限场景不可被恶意注入5. TDISP与IDE的协同完整性和机密性如何落到TLP头上TDISP管能不能走IDE管走得安不安全。两者经常被混为一谈但在规范里分工明确下面把协同关系拆开讲。5.1 IDE的两种封装粒度与TLP的关系IDE可以在链路层Link IDE和传输层TLP IDE两个层级工作。链路层IDE对整个链路上的所有TLP做完整性保护粒度粗、实现相对直接传输层IDE则是选择性地对部分TLP加封装通常配合TDISP的规则使用——只有TDISP允许通过的TLP才需要被IDE保护。这种选择性保护的设计很聪明它避免了对所有报文都进行密码运算把性能代价控制在需要保护的范围内。一个典型的TLP IDE封装过程大致是原始TLP头部保持不变在头部后面追加IDE扩展头包含完整性校验值、流标识、标签等字段然后整个报文再经过链路层的CRC保护。对接收侧来说先做链路CRC校验再去掉链路层封装然后解析IDE扩展头并校验完整性。任何一步失败都说明报文被篡改过设备会把这当作安全事件上报。5.2 IDE Stream与TDISP接口的绑定IDE规范里引入了Stream的概念——一条Stream就是一组共享相同安全上下文密钥、完整性算法等的TLP流。TDISP的接口安全状态与IDE Stream之间存在明确映射关系一个处于LOCKED状态的接口其允许通过的TLP必须归属到该接口对应的IDE Stream上。换句话讲TLP不仅要类型对、地址对还要流对。我在初次实现时踩过一个坑给两个接口配置了相同的Stream标签结果DIF和IDE之间的联动规则出现了竞态A接口的TLP被IDE校验通过但被B接口的策略放行——这在多接口场景下就是严重的安全漏洞。最终的解法是每个接口独立分配Stream标签并在DIF的过滤逻辑里同时校验Stream ID和接口ID。5.3 完整性校验失败后的系统行为当IDE完整性校验失败时设备不能假装没看见。规范的要求是丢弃该TLP记录安全事件并推动相关接口进入UNDER_FIRE状态。有些实现还会向系统管理软件发送安全日志消息这样管理平面能快速定位是哪个接口出了问题。这里要注意一个顺序问题先由IDE层报告完整性错误再由TDISP层决定该接口的状态迁移。如果DIF发现错误是由于配置参数错误导致的它可能只会隔离到接口级别并允许软件恢复如果发现错误持续出现则可能直接要求整个设备复位。具体策略是设备厂商的Policy决定但无论如何静默忽略是绝对不允许的。6. 从规范到落地设备侧和软件侧的配合要点TDISP的学习曲线比较陡最大的障碍往往不是概念本身而是看懂了规范却不知道从哪下手实现。我把个人实践中的经验做一次总结供正在做PCIe安全功能的朋友参考。6.1 设备侧实现的大致步骤以FPGA为例如果你的设备是FPGA要在设计中加入TDISP支持我建议按下面四步推进。第一步是实现SPDM认证。TDISP的安全上下文建立必须依托已经认证过的设备身份所以设备固件或逻辑里要先能响应SPDM的Challenge/Response流程。FPGA上做这一步一般是软核实现因为涉及证书解析和签名运算放在硬逻辑里代价太高。第二步是搭建DIF状态机。按照规范的状态转换图为每个接口定义一个状态寄存器并实现消息解析逻辑。消息解析主要吃MMIO接口需要规划好寄存器地址空间避免和BAR的原有功能冲突。第三步是加入TLP过滤器。粗粒度过滤可以放在PCIe硬核后端Receive/Transmit路径上细粒度校验需要放在事务层。这里要特别关注Completion路径的校验很多漏洞都出在这个环节。第四步是接入IDE引擎。如果FPGA硬核自带IDE支持直接配置Stream即可如果没有则需要自己做加密模块并与DIF联动。这一步的工作量最大建议优先复用成熟IP核。6.2 软件驱动的配合要点TDISP的配置命令大多需要由运行在TEE内的驱动发出所以驱动代码要遵循这样一个顺序先通过SPDM拿设备证书并验证再向DIF发送创建会话命令配置DMRS和中断向量表最后发送LOCK命令。如果驱动在LOCK之后发现设备接口进入UNDER_FIRE应当先读取DIF的事件寄存器确认是哪种违规再做恢复操作——通常是通过RECOVER命令重置该接口的安全状态前提是驱动能证明自己仍持有正确的会话密钥。这里的能证明不是空话规范要求恢复操作必须附带安全凭证比如一次性令牌或会话ID防止攻击者伪造恢复指令。实现时这些令牌的生成逻辑要和SPDM会话绑定不能写死。6.3 学习路线建议先SPDM再IDE最后TDISP如果完全不熟悉PCIe安全体系我强烈建议按SPDM - IDE - TDISP的顺序学。SPDM解决的是认证与密钥协商的问题是基础IDE解决的是报文怎么保护的问题是和链路直接相关的部分而TDISP则是在这两者之上的一套策略层规则。跳过前两者直接看TDISP你会经常遇到为什么这里要绑Stream为什么这个密钥要在这里生成的疑问很容易绕晕。把顺序倒过来每个概念都能落在实处。7. 实际调试中的几个真实案例与经验教训最后分享几个我在调试TDISP相关逻辑时真实踩过的坑希望能帮你少走弯路。第一个坑是Completion路径过滤缺失。前面提过很多实现只过滤Request方向Completion方向不设防。我在做注入测试时构造了一个越界的Memory Read请求设备正确拦截了请求本身但因为没有检查Completion返回DIF依然把一个伪造的Completion送达了驱动整个过滤等于被绕过。后来我把Completion校验逻辑补上并且对每个未完成的读请求增加超时和状态清理机制这个问题才彻底关掉。第二个坑是中断过滤表配置顺序。一开始我把MSI-X允许向量表的更新放在设备运行期动态执行结果出现一个窗口驱动刚下发更新中断已经触发旧向量与新手势交织导致通知到了错误的目的地。规范本身的约束是允许表必须在LOCK之前配置完毕LOCK之后不再变化。遵循这个约束后运行期的中断行为变得可预测了调试难度大幅下降。第三个坑是IDE Stream和DIF策略的竞态。这个案例前面提过多接口共用Stream标签导致策略评估混乱。排查过程费了不少时间因为问题不是稳定复现的——只有当两个接口同时发起高带宽DMA时才出现偶发越权。最后靠抓取运行时的Stream ID比对才定位到。这个教训是设计阶段就要把Stream ID当作与Request ID同级的过滤键值来对待不能只依赖IDE子系统的内部分配。这些坑在规范文档里都很难直接看到它们属于硬件与软件协同设计层面的问题。如果你也在做类似的功能建议把TLP过滤设计和IDE配置放到一起评审而不是分成两个独立的模块来验证。因为TDISP的安全边界最终是穿越这两个模块的割裂设计一定会漏。TDISP确实是PCIe协议学习里最需要耐心的一块。它不像LTSSM那样有清晰的时序图可以依葫芦画瓢也不像枚举过程那样可以通过抓包快速验证。它的核心价值体现在策略与执行分离的设计思想上而这种思想要靠把TLP规则、地址范围、中断向量和IDE流绑在一起才能体现出来。下一篇我打算深入状态机的转换细节顺带把DIF消息的寄存器级交互展开写其中会涉及不少和SPDM交互的细节感兴趣的可以先复习一下SPDM的Challenge-Response流程和证书模型后面会直接用。
02
RELATED NEWS

相关资讯

更多网站建设与数字化升级内容

03
WHY YAOTU

想打造同款高转化官网?

懂行业、懂生意,从建站到增长一站式陪跑

◈

场景化定制

不做模板站,围绕你的业务场景量身设计,小众不撞款。

◐

营销型架构

以转化目标组织内容与路径,让官网真正带来询盘。

▲

全周期服务

设计、开发、运营、运维一体,上线只是开始。

免费获取你的建站方案

留下需求,专属顾问 24 小时内为你输出方案建议。