仓库源文

.. Kenneth Lee 版权所有 2021

:Authors: Kenneth Lee :Version: 1.0 :Date: 2021-08-10 :Status: Release

逻辑正交


最近看到一个关于逻辑正交的例子,通过本文记录下来。

有人在实现一个IOMMU方案,其中一个特性是PRI(Page Request Interface)。PRI是一个 PCIe的功能,用于在设备做DMA的时候,如果页表不在位,报一个缺页异常给CPU,让CPU把 这个页填上,之后设备就可以访问这一页了。

这和CPU访问内存的时候MMU翻译不了,在CPU产生一个异常,让异常向量把页补上很相似。

说起来是这样,但深入分析这个逻辑,或者进行功能验证后就会发现,其实不是这样的。

对CPU来说,一条内存访问指令在执行的过程中,发生了异常,在CPU的语义中,这条指令 还没有结束,CPU先挂起这条指令,触发一个异常,CPU继续执行,补上这一页。虽然从软 件的角度来说,访问内存的应用,和OS是异常处理向量,是两个对象。但从CPU的角度来说 ,这是一个连续的过程:访存指令前半段-异常向量-访存指令重启。这里CPU资源一直占用 着。

但IOMMU不是这样。对IOMMU来说,一个设备发起了一个访存,IOMMU异常,让设备等着,这 不经济。因为设备,IOMMU和CPU不是同一个对象。所以PRI协议的定义是这样的:设备给 IOMMU\ [#iommu]_\ 发地址请求,地址请求失败了,IOMMU通知设备,设备再发PRI,请求 CPU去补页,CPU完成补页了,通知设备,设备重新发地址翻译请求。

在这个逻辑中,我们理所当然地认为,这是一个连续的会话。但其实在IOMMU眼中,它不感 知这个会话的存在。我们想想哈:你设备给我IOMMU一个地址翻译请求,我翻译不了,给你 报错,这个事情就结束了。这个事情你是因为哪件事情而要求我翻译,没有任何关系吧? 然后,你通过我给CPU发PRI,是因为哪个事情而发的,也和我没有关系吧?你发给了CPU, CPU不理你,我也管不着吧?

这种情况下,IOMMU就不感知会话,就不会记住当前是哪个会话的。会话的概念完全出现在 设备上,甚至和CPU都没有关系。这里,会话这个概念,就叫和IOMMU和CPU“逻辑正交”。因 为我认知你这个概念,我不能特别对它做点什么。

我们做架构经常希望正交的逻辑闭包可以被独立出来,因为这样我们的系统更容易被拆开 。在上面这个设计中,很多人一不小心就会掉到“在IOMMU中管理一个访问的会话”这个陷阱 中。要避免这种陷阱,我们必须对逻辑闭包的条件整理得很清楚,如果我们通过设计文档 单独列出每个逻辑闭包(概念空间)设计的所有概念,我们就很容易注意到,有一些条件 是和其他条件是完全独立的。这样我们就很容易把这种“正交”的条件,独立移出这个空间 了。

.. [#iommu] 如果从标准上说,PCIe不认IOMMU,它用RC这个抽象来代表所有CPU提供的功能, 但实现的时候,很多RC的实现都是靠IOMMU来支持的。