Linux内核工程导论——UIO


要开启hugepages文件系统,这个文件系统要使用mmap来映射页,可以显著的减少缺页中断。

UIO介绍

UIO是一个在用户端实现内核驱动的机制。其在内核中有一个模块支持uio模块。现在这个模块只支持字符设备。用户可以添加多个uio设备(用户端的设备驱动),每个设备在/dev/uioX,X为数字,第一个为0,依次类推。我们知道设备都是靠中断来响应的,响应uio设备中断的方法是读取/dev/uioX文件,没有中断的时候读取会阻塞,来中断的时候会读取到整数值,代表已经发生的中断的次数。

但是这只是一般情况,有的设备有多个中断,有的没有中断。针对这些情况uio也实现了对应的机制,但是实现称不上完美。对于多个中断的情况,对/dev/uioX进行write()系统调用可以打开或者关闭内核的中断处理,以便驱动可以手动处理中断。没有中断的情况,uio提供了一个定时器接口,通过设置这个接口可以人工的让这个设备定时产生中断。

对于UIO用户定义的驱动,类似内核驱动,一般会有一些需要通过sys文件系统访问的全局变量。uio不支持调用sysctl更改这些值,但是可以在sys文件系统找到这些对应的文件,从而进行修改:/sys/class/uio/uioX

每个uio设备都有name、version、event这3个定义属性,还有一个maps文件夹(有内存映射的时候才存在),其他为sys文件系统自带的uevent模型。name表示这个UIO设备的名字,version用于标示当前的uio内核模块的版本,event与read() 设备获得的值一样,是当前已经发生过了中断的次数。maps文件夹服务于硬件的数据处理。大部分硬件都需要操作内存,UIO用户驱动如果要映射设备内存到用户端操作,需要使用mmap系统调用,每使用一次系统调用会在maps目录下生成一个目录map[digital],里面有4个固定的文件用来描述映射的内存的信息:

其中addr是映射的基地址,offset是偏移量,name是映射时给这段映射起的名字,size是映射的内存的大小。如果不能映射内存的话,还可以通过x86的端口操作系统调用ioperm(), iopl(), inb(), outb()等对某个硬件端口进行读写。这种情况下,uio模块还添加了/sys/class/uio/uioX/portio/目录,下面是各个模块的文件映射,使得用户仍然可以直接操作端口来改变配置。

由于UIO在用户空间写驱动的便利性,所以对FPGA提供了很好的支持,甚至dpdk这种将内核数据包导出到用户空间的机制也是使用UIO的。Open Source Automation Development Lab等使用机器人编程的组织也喜欢UIO。

IOMMU

IOMMU本来是为虚拟化而设计,使用场景是如果驱动在用户态(比如虚拟机),没有高效的使用设备IO内存的方法,内核要在用户内存空间到设备内存空间做额外的转换,IOMMU可以直接将设备的内存空间映射到用户进程空间。用户可以直接排它的操作硬件。

VFIO

则是软件对硬件设备内存暴漏在用户空间的支持,DMA内存直接被映射到用户进程空间,使用这个驱动需要将设备与操作系统原来的驱动解绑。目前仅实现了支持vfio-pci模块支持PCI设备的映射。这对于在虚拟机和用户空间设备驱动有重要意义。

相关内容

    暂无相关文章