在之前的一篇文章用devmem2读写设备IO内存中,我介绍了devmem2
这个通过读写/dev/mem
文件实现从用户空间访问外设寄存器的工具,但是对于PCIE设备,特别是FPGA模拟出来的自定义PCIE设备,该工具在x64平台下可能会发出64位的内存读写请求,而FPGA模拟的外设寄存器一般都映射到32位地址空间,此时CPU就会因FPGA工作不正常而卡死。
此时驱动必须用ioread32接口来读写外设寄存器,而该接口无法被用户程序调用,不利于调试,最好有一种既能从用户空间访问,又能避免PCIE发出64位地址访问请求的方法。
现在较新的内核(4.15+)都支持sysfs,且每个PCIE设备都对应一个目录
/sys/bus/pci/[domain]:[bus]:[device].[function]/
该目录下有这些属性文件(有删减):
tree /sys/bus/pci/devices/0000\:01\:00.0/
/sys/bus/pci/devices/0000:01:00.0/
├── class
├── config
├── device
├── dma_mask_bits
├── driver -> ../../../../bus/pci/drivers/f260_mainfpga
├── enable
├── reset
├── resource
├── resource0 //对应BAR0寄存器空间
├── resource1 //对应BAR1寄存器空间
├── uevent
└── vendor
只要将resource0
这样的属性文件
像/dev/mem
文件一样mmap
到用户进程的虚拟地址空间,就可以像devmem2
工具那样通过解引用的方式访问寄存器,而不用ioread32
/iowrite32
等内核函数。
有人已经提供了现成的工具pcimem,不过github时常抽风,我转载到了我的gitee以供下载
该工具用法跟devmem2很像(因为代码是基于devmem2修改的)
Usage: ./pcimem { sysfile } { offset } [ type*count [ data ] ]
sys file: sysfs file for the pci resource to act on
offset : offset into pci memory region to act upon
type : access operation type : [b]yte, [h]alfword, [w]ord, [d]ouble-word
*count : number of items to read: w*100 will dump 100 words
data : data to be written
sudo ./pcimem /sys/bus/pci/devices/0001\:00\:07.0/resource0 0x100 w 0x00
BAR0 寄存器偏移 访问粒度word 写入0x00(读的话不填该参数)
个人猜测是resource属性文件的驱动代码实现了普通内存地址到io内存地址的转换。