我目前正在 Xilinx Zynq Ultrascale+ 板上的 Linux arm64 中创建共享虚拟地址空间。将来,应该可以利用内置的 ARM SMMU 500 (IOMMU) 和缓存一致性接口 (CCI) 在 Cortex A53 和 FPGA 之间共享指针/地址,而无需任何用户操作。
为此,我使用了 Linux 内核 v4.14.0 的 driver/iommu/arm-smmu.c iommu 驱动程序,并对其进行了修改以删除大部分虚拟化抽象,以及单独的自定义内核模块和 ioctl。因此,每个进程都有自己的 SMMU 上下文库,其中包含自己的 aarch64 页表。现在已经可以通过手动将分配的页面再次映射到相同的虚拟地址,使用单独的页表成功地从具有虚拟地址的FPGA读取和写入数据。
如果MMU和SMMU可以共享相同的页表,那么会更方便,从而避免不必要地设置第二个冗余页表。为此,我进行了以下更改:
配置 SMMU 以使用 39 位 VA 大小和 40 位 PA 大小(4 KB 页大小)
从 curr task_struct 中取出 PGD 指针并将其传递给正确的 SMMU 上下文库 PGD (TTBR) 条目
所有其他 SMMU 硬件配置与 arm-smmu.c 中的相同。
然而,这会导致非确定性行为。 FPGA 读取多个值并使用共享虚拟地址将它们写回不同位置的测试用例有时仅有效。我实现了测试程序,在设置所有必要的数据结构并初始化它们之后以及指示 FPGA 传输值之前有意暂停。暂停时间越长,正确传输的值就越多。暂停大约 10 秒后,测试总是成功结束。在我看来,这听起来像是一个缓存问题,其中 Linux 创建的更新页表条目 (PTE) 仍在 CPU 缓存中,并且 SMMU 访问错误的页表条目,从而导致无法传输(但 SMMU 中也没有转换错误/故障) 。因此,我要么必须在 Linux 源代码中的正确位置刷新/清理缓存,要么更改一些 SMMU 标志(上下文库、流 2 上下文寄存器……)、MMU 标志或 PTE 的内存/可共享性标志。
我已经发现 SMMU 的 MAIR 设置不同。我更改了 SMMU 代码以匹配 MMU 的 MAIR,并在必要时使用正确的内存属性索引。但这没有用。此外,我还检查了ARM SMMU v2架构规范中的第1.5.2章“ARM架构和SMMU翻译方案之间的差异”。
最让我困惑的是,手动构建的页表可以正常工作,但 Linux 生成的页表会导致所描述的不确定性行为。
有关如何正确设置 SMMU 以使用/共享 Linux 生成的页表或更改 Linux 配置其页表的方式以便与 SMMU 正常工作的任何信息或提示?