在Linux中,用户程序是否总是使用对操作系统内核的系统调用来间接访问设备驱动程序?
当驱动程序实现为可加载和卸载的模块时,用户程序是否可以直接访问驱动程序而无需对内核进行系统调用?
答案1
用户调用环绕系统调用的库函数(原始系统调用对于普通程序员来说非常罕见)。无论如何,模块代码都在内核模式下运行,因此在某些时候,必须存在从用户空间到内核空间的上下文切换。理想情况下,大多数模块将使用标准化接口(设备节点,netlink套接字,甚至inet套接字),因此用户端的交互将主要通过系统read()
调用write()
(ioctl
也很常见,因为它涵盖了“额外”设置不属于标准系统调用)。缓冲区会减少调用次数,但最终总会涉及系统调用。
答案2
内核模块存在于内核空间中,因此根据定义需要系统调用才能从用户空间访问,因此是的关于他们。
但是,可以创建构建在某个内核驱动程序之上的用户空间驱动程序,尽管最终它们必须进行系统调用才能运行。这对于 I 2 C 设备来说是可能的;用户空间驱动程序使用内核的 SMBus API(所有系统调用)。在这种情况下,某些应用程序可能在技术上使用驱动程序的某些功能而不通过系统,但如果驱动程序实际上必须与硬件交互,那么它又是系统调用。
还可以mmap()
在 上使用(系统调用)/dev/mem
,这是系统内存(请参阅 参考资料man mem
),并且由于这包括整个内核空间,因此公开了对硬件的访问。然后操纵这张地图才不是需要任何进一步的系统调用。我相信这是一件不寻常的事情,部分是因为它以一种可能不受欢迎的方式回避了内核本身,部分是因为使其从一种体系结构移植到另一种体系结构会涉及冗余1——因此它更有可能被使用与生产系统中的驱动程序部署相比,更适合黑客攻击和实验。
内核驱动程序可以向用户空间公开基于设备节点的接口,该接口可以使用read()
和进行操作write()
- 这是系统调用。
1. 如果你编写一个普通的内核驱动程序,或者使用内核用户层API,内核本身就涵盖了可移植性问题;您可以坚持使用代码的一个版本。如果您使用内存映射方法,则必须为每个体系结构拥有不同版本的代码(内核已经拥有,因此是“冗余的”)。