内核驱动程序和内核模块之间有什么区别?


66

当我lspci -k使用3.2.0-29-通用内核在Kubuntu上执行操作时,我会看到类似以下内容:

01:00.0 VGA compatible controller: NVIDIA Corporation G86 [Quadro NVS 290] (rev a1)
    Subsystem: NVIDIA Corporation Device 0492
    Kernel driver in use: nvidia
    Kernel modules: nvidia_current, nouveau, nvidiafb

有一个内核驱动程序nvidia和内核模块nvidia_currentnouveaunvidiafb

现在我想知道内核驱动程序和内核模块之间有什么区别?

Answers:


78

内核模块是一些编译后的代码,可以在运行时插入到内核中,例如with insmodmodprobe

驱动程序是在内核中运行以与某些硬件设备通信的一些代码。它“驱动”硬件。计算机中的大多数硬件都有相关的驱动程序。¹运行中的内核的很大一部分是驱动程序代码。²

可以将驱动程序静态地内置到磁盘上的内核文件中。³也可以将驱动程序构建为内核模块,以便以后可以动态加载。(然后卸载。)

标准做法是在可能的情况下将驱动程序构建为内核模块,而不是将其静态链接到内核,因为这样做可以提供更大的灵活性。但是,有充分的理由不这样做:

  • 有时,绝对有必要使用给定的驱动程序来帮助系统启动。由于有initrd功能,这种情况并不像您想象的那么频繁。

  • 在静态范围内的系统(例如嵌入式系统)中,静态构建的驱动程序可能正是您想要的。也就是说,如果您事先确切地知道将始终需要哪些驱动程序,并且永远不会改变,那么您就有充分的理由不去理会动态内核模块。

  • 如果您静态构建内核并禁用Linux的动态模块加载功能,则可以防止在运行时修改内核代码。这以灵活性为代价提供了额外的安全性和稳定性。

并非所有内核模块都是驱动程序。例如,Linux内核中的一个相对较新的功能是您可以加载其他进程调度程序。另一个例子是,更复杂的硬件类型通常具有位于低级硬件驱动程序和用户区之间的多个通用层,例如USB HID驱动程序,它实现了USB堆栈的特定元素,而与底层硬件无关。


助手

  1. 有一个例外,这个广泛的说法是CPU芯片,它没有“驱动程序” 本身。您的计算机可能还包含您没有驱动程序的硬件。

  2. OS内核中的其余代码提供了通用服务,例如内存管理IPC调度等。这些服务可能主要为用户区应用程序提供服务,就像前面链接的示例一样,或者它们可能是驱动程序或其他内部使用的内部服务。内核基础结构。

  3. 引导过程的早期,/boot引导加载程序在引导时加载到RAM中的一个。


1
模块可以是文件系统,网络协议,防火墙功能等等。一些硬件(例如WiFi卡)需要一堆模块,一些提供通用的基础结构,而另一些则处理硬件本身。
vonbrand 2015年

1
这是一个很好的概述,但是我有与OP完全相同的问题,然后遇到了这个答案,但仍然不知道为什么“使用中的驱动程序”与“模块”不同。相反,@ Jim Paris的答案是正确的。来自man lspci:“ -k显示处理每个设备的内核驱动程序,以及能够处理该设备的内核模块。” 您可能会读为:“显示当前/实际正在处理设备的驱动程序,以及可能/打算处理该设备的所有模块 ”。
Binarus

如果您知道Windows:模块与DLL非常相似。在Unix上,模块类似于共享库,但是模块仅用于内核。动态链接的模块可以包含驱动程序。内核可以包含静态链接的驱动程序。模块与DLL(或.so)不同,因为内核对如何动态加载事物有特定的要求。
robocat

18

为了回答有关lspci输出的特定问题,“内核驱动程序”行指的是当前与卡绑定的驱动程序,在本例中为专有nvidia驱动程序。“内核模块”行列出了所有已知能够绑定到该卡的驱动程序。在这里,专有驱动程序为它显示了一个不同的名称,这可能是由于lspci该驱动程序及其文件名与编码到驱动程序本身中的名称的查找方式有关。


谢谢-有所帮助。如果我只发表过man lspci-它说的正是您写的。
Binarus

5

根据这个不错的教程

...一种类型的模块是设备驱动程序,它允许内核访问连接到系统的硬件。

因此,如果我们尝试绘制一棵树,我们将拥有“设备驱动程序”,它继承自(扩展)模块,并且具有更具体的特征,在这些特征之间我们可以找到“对硬件的访问” ...


这只是部分正确。驱动程序是层次结构中某个类的对象(是的,Linux的内部设计,如当前大多数操作系统一样,是面向对象的)。但是所说的驱动程序可能是一个模块(在运行时可加载)或编译到内核中。在代码方面,备选方案之间没有(或很小)差异。
vonbrand 2015年

4

内核模块可能根本不是设备驱动程序。

“内核驱动程序”不是一个定义明确的术语,但让我们来看看。

这是一个内核模块,不驱动任何硬件,因此不能合理地视为“设备驱动程序”:

#include <linux/module.h>
#include <linux/kernel.h>

MODULE_LICENSE("GPL");

static int myinit(void)
{
    printk(KERN_INFO "hello init\n");
    return 0;
}

static void myexit(void)
{
    printk(KERN_INFO "hello exit\n");
}

module_init(myinit)
module_exit(myexit)

构建后,可以将其用于:

insmod hello.ko

并打印hello initdmesg

但是,有些内核模块不是设备驱动程序,但实际上是有用的,例如,公开内核调试/性能信息的模块。

设备驱动程序通常也是内核模块。

作为“设备驱动程序”的示例很难生成,因为它需要硬件来驱动,并且硬件描述往往很复杂。

但是,使用QEMU或其他仿真器,我们可以构建真实或简化硬件的软件模型,这是学习如何与硬件对话的好方法。这是最小PCI设备驱动程序的简单示例:https : //github.com/cirosantilli/linux-kernel-module-cheat/blob/6788a577c394a2fc512d8f3df0806d84dc09f355/kernel_module/hello.c

然后我们看到在x86中,与硬件的对话归结为:

这些操作通常不能从用户空间进行,如以下内容所述:用户空间和内核空间之间有何区别?但是,有一些例外:https : //stackoverflow.com/questions/7986260/linux-interrupt-handling-in-user-space

然后,内核提供了更高级别的API,以使这种硬件交互更加容易和可移植:

  • request_irq 处理中断
  • ioreadX 和IO内存映射
  • 甚至更高级别的接口,用于诸如PCI和USB的流行协议

0

我的答案会和吉姆一起去。内核驱动程序是旨在驱动硬件的程序(内核模块)。lspci输出显示nvidia是内核驱动程序,因为它是loaded设备的模块。随之而来的还有其他可用的内核模块。

我将添加Linux中列出和删除驱动程序的命令分别为lsmodrmmod。其中列出模块和删除模块。


0

所有驱动程序都是模块。并非所有模块都是驱动程序。

可以在运行时插入模块。模块/驱动程序也可以与内核一起静态编译。

典型的模块初始化有

module_init(init_fn);
init_fn()
{
   /* some code */
}

相同的模块可以成为驱动程序

module_init(init_fn);
init_fn()
{
   device_register(&device);
   /* some code */
}

8
驱动程序并不总是模块,它们可以包含在主内核映像中。
Gilles 2012年

3
@Prabagaran:“所有驱动程序都是模块。所有模块都不是驱动程序。” 这是矛盾的。用数学术语来说,您所说的是D-> M和M->!D。这允许D和!D。
Francesco Turco 2012年

2
我认为他的意思是“所有驱动程序都是模块。并非所有模块都是驱动程序”。
雷南2012年

4
@Renan:那是正确的,但是如果您查看此答案的编辑历史记录,则已经有人试图解决该错误,而作者将其恢复了。通常,我只是进行编辑以修复错误并继续进行,但是在这种情况下,我已执行-1,因为这是错误的并使问题令人困惑。
Caleb 2012年

我记得(有一段时间没有上当),有些驱动程序无法构建为可加载模块。我似乎记得其他人只能作为模块来处理。
vonbrand 2015年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.