smmuv3的父设备的代码里有:
1 | smmu_base_realize |
把一个获取as的方法放到了PCIBus里,一般的这个方法是有IOMMU驱动定义,IOMMU驱动为
IOMMU管理的设备在IOMMU驱动里建立一个数据结构存储相关信息,这个信息里就有设备对应
的AS。通过这个方法,使用设备的bdf作为输入,后续设备可有拿到他自己对应的AS。
设备随后发dma的时候通过他自己的AS得到smmu里的translate函数然后做翻译。
我们可以看一个具体的intel e1000的虚拟网卡:qemu/hw/net/e1000.c
在这个设备注册的时候会调用:
1 | /* qemu/hw/pci/pci.c */ |
设备模拟一个dma读写的实现:
1 | pci_dma_read/write |
可以看到这个函数后面的调用链里会最终调用到iommu里的translate函数,然后对翻译
都的地址读写。
对于普通的DMA,如上已经够了。但是,对于带PASID的翻译请求,现在还没有支持的逻辑。
我们查看具体的translate函数的入参:
1 | IOMMUTLBEntry (*translate)(IOMMUMemoryRegion *iommu, hwaddr addr, |
我们可以用最后一个参数iommu_idx去传递pasid给具体的翻译函数,这个iommu_idx不能直接
使用,在使用前需要通过attrs_to_index这个函数把MemTxAttrs attrs翻译成iommu_idex。
所以,想要在当前的smmu驱动里支持pasid,就要在smmu驱动的imrc里实现attrs_to_index
的回调函数。如果我们的输入把attrs数值上相等映射成iommu_idx,attrs_to_index可以
是如下这样:
1 | static int smmuv3_attrs_to_index(IOMMUMemoryRegion *iommu, MemTxAttrs attrs) |
对应的我们给设备驱动可以提供这样的带PASID的DMA读写函数:
1 | static inline int pci_dma_rw_pasid(PCIDevice *dev, dma_addr_t addr, |