嵌入式Linux中文站

linux内核通讯简介


根据wiki(http://en.wikipedia.org/wiki/User_space)的介绍可知,操作系统经常使用
虚拟内存来隔离内核空间和用户空间。内核空间被严格地保留着运行内核、设备驱动及
内核扩展程序。在大多数操作系统里,内核的内存永远不会交互到磁盘上。用户空间则
是所有用户态程序运行的内存空间,当需要时这块空间可以被交换到磁盘上。
一个应用程序不能直接访问内核空间,类似的,内核代码在没有检查一个页是否在内存
中或交换到磁盘上时也不能访问用户空间。虽然它们之间不能直接互相访问,用户空间
和内核空间可以通过不同的方法来互相通讯。这里试图对linux下使用的方法进行总结:

系统调用
正如syscall手册中解释,系统调用时用户和内核直接基础的接口。
系统调用是指一个运行的任务向内核请求提供代表内核自己的某种服务。一般地,由系
统调用所唤起的内核服务包含了一个抽象层,它介于硬件和用户空间程序之间。
系统调用的处理方式依赖于处理器。对内核的调用经常引起一个中断或异常;在调用中
,总是有请求执行一些特殊的事务。
system_call实体的真正代码可以在/usr/src/linux/kernel/sys_call.S中找到(译注:
没找到),许多系统调用的代码可以在/usr/src/linux/kernel/sys.c中找到。剩余的代码
分布在其他源代码中。一些系统调用,比如fork,有其自己的源代码(比如kernel/fork.
c)
优点:  说明文档丰富,接口容易使用

ioctl
虽然ioctl也是一种系统调用,但它的用处还是吸引我来单独讨论它。有时候被比喻为瑞
士军刀,ioctl代表了输入/输出控制并被用于通过一个文件描述符来操纵一个字符设备
。ioctl就像万花筒,可以处理设备、请求、各种各样的参数,它们都在相关头文件中定
义。
优点: 向应用程序提供硬件层访问机制
缺点:设备和需求缺少文档,且和平台相关

proc文件系统
/proc文件系统(procfs)是linux内核里一种特殊的文件系统。它是一个虚拟的文件系统
,也就是说并不和某个块设备关联而只存在与内存之中。
procfs里的文件是允许用户程序访问的,用于从内核中获取某些信息(比如/proc/[0-9]+
/中的进程信息),也可用于调试(比如/proc/ksyms)(译注:没找到)
优点:可以通过命令行使用统一接口来获取进程信息
缺点:通过单个文件系统展示了太多的信息,很难提取出所需信息

Sysfs
Sysfs是2.6Linux内核提供的虚拟文件系统。Sysfs从内核设备模块中导出设备信息和驱
动信息到用户空间,也可以用于进行配置。
Sysfs设计出来是为了导出展现在设备树中的信息,这样再也不会把procfs弄乱掉。
对于每个加载到驱动模块树中的对象(驱动,设备,设备类型),sysfs都会创建一个目录

其中的父子关系是通过/sys/devices/下的子目录来反应出来的(反映了其物理层次构造)
。子目录/sys/bus/下都扩展成符号链接,反映出设备是如何属于不同的总线的。/sys/c
lass/显示了根据类型划分的设备群,比如网络设备群,而/sys/block包含了块设备。
优点:统一的接口来获取/更新设备的指定信息

Netlink sockets
Netlink socket是一种特殊的IPC,用于在内核和用户空间的进程间传递信息。它在两者
间提供了全双工的通讯连接,用户空间进程使用普通的socket API,内核模块使用指定
的内核API。
Netlink socket使用AF_NETLINK地址族。
用户空间的应用程序可以通过标准的socket API-socket(), sendmsg(), recvmsg()
and close()来访问netlink socket。
优点: 为了新特性而增加系统调用、ioctl或proc文件可是件大事;需要冒着污染内核和
破坏系统稳定性的风险。netlink socket很简单,只需通过往netlink.h中添加一个常数
,协议类型。

relay
Relayfs是另一个内核所实现的虚拟文件系统;它必须有用户空间来明确地加载以使得其
可用。内核代码负责用relay_open()曾经一个relay块;在relayfs下它表现为一个文件

用户空间然后就可以打开这个relay块并实施所有常见的文件操作-包括mmap()和poll()
-用于和内核交换数据。
对于应用程序而言,一个relayfs文件描述符非常像是一个unix-domain socket,只是另
外一头是一堆内核代码而非一个进程。
内核端口的接口稍微复杂些。relay_read()和relay_write()函数用于从用户空间移入和
移出数据。
但是relayfs也向内核代码暴露了太多的内部结构,内核必须了解这些。因此用于特殊目
的的代码可用包含一个指向relayfs缓冲区的指针来直接拷贝数据。
优点:很容易从内核空间输入输出大量信息。

debugfs
debugfs是一个内核中的文件系统,仅用于将调试信息输出在某处,和proc和sysfs不同
,它更容易使用。
debugfs是一种将内核开发者需要看的信息输出到用户空间的方法,而不总是需要挂起。
为了创建一个使用debugfs的文件,只需调用
struct dentry *debugfs_create_file(const char *name, mode_t mode, struct
dentry *parent, void *data, struct file_operations *fops);
为了导出一个数值到用户空间:
struct dentry *debugfs_create_u8(const char *name, mode_t mode, struct
dentry *parent, u8 *value);
就是这样,一行代码就可用使一个数值从用户空间导入导出
优点:调试信息更容易获取使得开发时间缩短

Firmware loading
尽管大多数的交换机外设都可以独立正常运行,一些外设还是需要从主机上下载二进制
固件程序,否则就无法正常工作
最终的解决方法就是设备需要一个用户空间进程来处理下载固件。
在新的方案中,一个需要固件的设备驱动会调用如下将接口:
int request_firmware(struct firmware **fw, const char *name, struct device
*device);
这里,name参数是指关联设备的名称,device参数是指设备模块实体。这个调用会创建
一个目录,其名称为/sys/class/firmware下的给定名称,并在目录下创建能够文件loadi
ng和data。当发生热插拔事件时,就会触发用户空间查找固件来支持其设备。

用户空间流程首先是设置加载sysfs属性为1后就开始运行。实际的固件就可以被写到dat
a文件中,当完成写操作后,加载文件应该被设置回0.此时,request_firmware()会返回
给驱动一个指向实际固件data的fw指针。用户程序可以通过将加载属性设置为-1来选择
放弃加载。

当驱动把固件加载到设备里,它就会调用下面这个接口来释放相关的内存
void release_firmware(struct firmware *fw);

虽然这只用于加载固件,但是有时候可以用于传输大量数据到内核空间。

本文永久更新链接:http://embeddedlinux.org.cn/emb-linux/entry-level/201011/25-1020.html



分享:

评论