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设备的映射。这对于在虚拟机和用户空间设备驱动有重要意义。

时间: 2024-10-24 16:00:04

Linux内核工程导论——UIO的相关文章

Linux内核工程导论——基础架构

基础功能元素 workqueue linux下的工作队列时一种将工作推后执行的方式,其可以被睡眠.调度,与内核线程表现基本一致,但又比内核线程使用简单,一般用来处理任务内容比较动态的任务链.workqueue有个特点是自动的根据CPU不同生成不同数目的队列.每个workqueue都可以添加多个work(使用queue_work函数). 模块支持 模块概述 可访问地址空间,可使用资源, 模块参数 用户空间通过"echo-n ${value} > /sys/module/${modulenam

Linux内核工程导论——进程

进程 进程调度 概要 linux是个多进程的环境,不但用户空间可以有多个进程,而且内核内部也可以有内核进程.linux内核中线程与进程没有区别,因此叫线程和进程都是一样的.调度器调度的是CPU资源,按照特定的规则分配给特定的进程.然后占有CPU资源的资源去申请或使用硬件或资源.因此这里面涉及到的几个问题: 对于调度器来说: l  调度程序在运行时,如何确定哪一个程序将被调度来使用CPU资源? n  如何不让任何一个进程饥饿? n  如何更快的定位和响应交互式进程? l  单个CPU只有一个流水线

Linux内核工程导论——用户空间设备管理

用户空间设备管理 用户空间所能见到的所有设备都放在/dev目录下(当然,只是一个目录,是可以变化的),文件系统所在的分区被当成一个单独的设备也放在该目录下.以前的2.4版本的曾经出现过devfs,这个思路非常好,在内核态实现对磁盘设备的动态管理.可以做到当用户访问一个设备的设备的时候,devfs驱动才会去加载该设备的驱动.甚至每个节点的设备号都是动态获得的.但是该机制的作者不再维护他的代码,linux成员经过讨论,使用用户态的udev代替内核态的devfs,所以现在的devfs已经废弃了.用户态

Linux内核工程导论——网络:Netfilter概览

简介 最早的内核包过滤机制是ipfwadm,后来是ipchains,再后来就是iptables/netfilter了.再往后,也就是现在是nftables.不过nftables与iptables还处于争雄阶段,谁能胜出目前还没有定论.但是他们都属于netfilter项目的子成员. 钩子 netfilter基于钩子,在内核网络协议栈的几个固定的位置由netfilter的钩子.我们知道数据包有两种流向,一种是给本机的:驱动接收-->路由表-->本机协议栈-->驱动发送.一种是要转发给别人的:

Linux内核工程导论——内存管理(一)

Linux内存管理 概要 物理地址管理 很多小型操作系统,例如eCos,vxworks等嵌入式系统,程序中所采用的地址就是实际的物理地址.这里所说的物理地址是CPU所能见到的地址,至于这个地址如何映射到CPU的物理空间的,映射到哪里的,这取决于CPU的种类(例如mips或arm),一般是由硬件完成的.对于软件来说,启动时CPU就能看到一片物理地址.但是一般比嵌入式大一点的系统,刚启动时看到的已经映射到CPU空间的地址并不是全部的可用地址,需要用软件去想办法映射可用的物理存储资源到CPU地址空间.

Linux内核工程导论——内核为何使用C语言

C与C++的对比无数人说过,都说C效率高,但很多人做过实验如果C++不使用RTTI,C++的效率也不会低太多(25%左右).还有人说C++强大的STL,但是对效率讲究点的话那个真的不能用,具体我后面说.一般大部分人的心态是,学C++出身的,就经常吐槽linux的C代码乱的一塌糊涂,各种敏捷,面向对象原则,代码不如C++精简,连个STL或者boost都用不上,等软件工程相关问题都是被他们吐槽的重灾区,这些人肯定没有给内核贡献过代码.做嵌入式一直用C的,接触内核后的反应是:啊,内核真大,啊,内核真难

Linux内核工程导论——用户空间进程使用内核资源

本文大部分转载和组装,只是觉得这些知识应该放到一起比较好. 进程系统资源的使用原理 大部分进程通过glibc申请使用内存,但是glibc也是一个应用程序库,它最终也是要调用操作系统的内存管理接口来使用内存.大部分情况下,glibc对用户和操作系统是透明的,所以直接观察操作系统记录的进程对内存的使用情况有很大的帮助.但是glibc自己的实现也是有问题的,所以太特殊情况下追究进程的内存使用也要考虑glibc的因素.其他操作系统资源使用情况则可以直接通过proc文件系统查看. 进程所需要的系统资源种类

Linux内核工程导论——网络:Filter(LSF、BPF)

数据包过滤 LSF(Linux socket filter)起源于BPF(Berkeley Packet Filter),基础从架构一致,但使用更简单.其核心原理是对用户提供了一种SOCKET选项:SO_ATTACH_FILTER.允许用户在某个sokcet上添加一个自定义的filter,只有满足该filter指定条件的数据包才会上发到用户空间.因为sokket有很多种,你可以在各个维度的socket添加这种filter,如果添加在raw socket,就可以实现基于全部IP数据包的过滤(tcp

Linux内核工程导论——内存管理(三)

用户端内核内存参数调整 /proc/sys/vm/ (需要根据内核版本调整) 交换相关 swap_token_timeout Thisfile contains valid hold time of swap out protection token. The Linux VM hastoken based thrashing control mechanism and uses the token to preventunnecessary page faults in thrashing s