您可以通过运行 lsmod 查看哪些模块已经加载到内核中,它通过读取文件来获取信息/proc/modules.
这些模块是如何进入内核的呢?当内核需要某个内核中没有的功能时,内核模块守护进程 kmod[1] 执行 modprobe 来加载模块。modprobe 接收一个字符串,格式为以下两种之一
类似这样的模块名称softdog或者ppp.
更通用的标识符,例如char-major-10-30.
如果 modprobe 收到一个通用标识符,它首先在文件/etc/modules.conf中查找该字符串。如果找到类似这样的别名行
alias char-major-10-30 softdog
它就知道该通用标识符指的是模块softdog.o.
接下来,modprobe 查找文件/lib/modules/version/modules.dep,以查看是否必须先加载其他模块才能加载请求的模块。此文件由 depmod -a 创建,包含模块依赖关系。例如,msdos.o需要fat.o模块已加载到内核中。如果另一个模块定义了请求模块使用的符号(变量或函数),则请求的模块依赖于另一个模块。
最后,modprobe 使用 insmod 首先将任何先决条件模块加载到内核中,然后加载请求的模块。modprobe 指示 insmod 到/lib/modules/version/[2],这是模块的标准目录。insmod 的目的在于对模块的位置相当“笨拙”,而 modprobe 则知道模块的默认位置。因此,例如,如果您想加载 msdos 模块,您必须运行
insmod /lib/modules/2.5.1/kernel/fs/fat/fat.o insmod /lib/modules/2.5.1/kernel/fs/msdos/msdos.o
或者直接运行 “modprobe -a msdos”。
Linux 发行版将 modprobe、insmod 和 depmod 作为名为 modutils 或 mod-utils 的软件包提供。
在结束本章之前,让我们快速看一下一段/etc/modules.conf:
#This file is automatically generated by update-modules path[misc]=/lib/modules/2.4.?/local keep path[net]=~p/mymodules options mydriver irq=10 alias eth0 eepro
以“#”开头的行是注释。空行将被忽略。
以下path[misc]行告诉 modprobe 将 misc 模块的搜索路径替换为目录/lib/modules/2.4.?/local。如您所见,shell 元字符是被支持的。
以下path[net]行告诉 modprobe 在目录~p/mymodules中查找 net 模块,但是,在path[net]指令之前的 “keep” 指令告诉 modprobe 将此目录添加到 net 模块的标准搜索路径,而不是像我们对 misc 模块所做的那样替换标准搜索路径。
别名行表示在 kmod 请求加载通用标识符 `eth0' 时加载eepro.o。您不会在
中看到类似 “alias block-major-2 floppy” 这样的行/etc/modules.conf,因为 modprobe 已经知道大多数系统上将使用的标准驱动程序。
现在您知道模块是如何进入内核的了。如果您想编写依赖于其他模块的自己的模块(我们称之为“堆叠模块”),那么还有更多内容。但这必须等到以后的章节再讨论。在解决这个相对高级的问题之前,我们还有很多内容要介绍。
在我们深入研究代码之前,我们需要讨论一些问题。每个人的系统都不同,每个人都有自己的习惯。让您的第一个 “hello world” 程序正确编译和加载有时可能是一个技巧。请放心,在您第一次克服初始障碍之后,一切都将一帆风顺。
为某个内核编译的模块,如果您启动不同的内核,将无法加载,除非您启用CONFIG_MODVERSIONS在内核中。我们将在本指南的后面部分讨论模块版本控制。在我们介绍模块版本控制之前,如果您运行的内核启用了模块版本控制,则本指南中的示例可能无法工作。但是,大多数库存 Linux 发行版内核都默认启用了它。如果您因为版本控制错误而无法加载模块,请编译一个关闭了模块版本控制的内核。
强烈建议您键入、编译和加载本指南讨论的所有示例。还强烈建议您从控制台执行此操作。您不应该在 X 环境中进行这项工作。
模块不能像printf()那样打印到屏幕,但它们可以记录信息和警告,这些信息和警告最终会被打印在您的屏幕上,但仅在控制台上。如果您从 xterm 中 insmod 一个模块,信息和警告将被记录,但仅记录到您的日志文件中。除非您查看日志文件,否则您将看不到它。为了立即访问这些信息,请从控制台完成所有工作。
通常,Linux 发行版会分发以各种非标准方式打补丁的内核源代码,这可能会导致问题。
一个更常见的问题是,某些 Linux 发行版分发不完整的内核头文件。您需要使用 Linux 内核中的各种头文件来编译您的代码。墨菲定律指出,缺少的头文件正是您模块工作所需的那些。
为了避免这两个问题,我强烈建议您下载、编译并启动一个全新的、库存 Linux 内核,该内核可以从任何 Linux 内核镜像站点下载。有关更多详细信息,请参阅 Linux 内核 HOWTO。
具有讽刺意味的是,这也可能导致问题。默认情况下,您系统上的 gcc 可能会在其默认位置而不是您安装新内核副本的位置(通常在/usr/src/中)查找内核头文件。这可以通过使用 gcc 的-I开关来解决。
[1] | 在早期版本的 Linux 中,这被称为 kerneld。 |
[2] | 如果您正在修改内核,为了避免覆盖现有模块,您可能需要使用内核 Makefile 中的EXTRAVERSION变量来创建一个单独的目录。 |