Many programming books begin with a "hello world" example as a way of showing the simplest possible program. This book deals in kernel modules rather than programs; so, for the impatient reader, the following code is a complete "hello world" module: 许多编程书籍都以“hello world”示例作为展示最简单程序的一种方式。 本书讨论的是内核模块而不是程序; 所以,对于没有耐心的读者,下面的代码是一个完整的“hello world”模块:
#include <linux/init.h>
#include <linux/module.h>
MODULE_LICENSE("Dual BSD/GPL");
static int hello_init(void)
{
printk(KERN_ALERT "Hello, world\n");
return 0;
}
static void hello_exit(void)
{
printk(KERN_ALERT "Goodbye, cruel world\n");
}
module_init(hello_init);
module_exit(hello_exit);
This module defines two functions, one to be invoked when the module is loaded into the kernel (hello_init) and one for when the module is removed (hello_exit). The module_init and module_exit lines use special kernel macros to indicate the role of these two functions. Another special macro (MODULE_LICENSE) is used to tell the kernel that this module bears a free license; without such a declaration, the kernel complains when the module is loaded. 该模块定义了两个函数,一个在模块加载到内核时调用(hello_init),另一个在模块被删除时调用(hello_exit)。 module_init 和 module_exit 行使用特殊的内核宏来指示这两个函数的作用。 另一个特殊的宏(MODULE_LICENSE)用来告诉内核这个模块带有免费许可证; 如果没有这样的声明,内核会在模块加载时抱怨。
The printk function is defined in the Linux kernel and made available to modules; it behaves similarly to the standard C library function printf. The kernel needs its own printing function because it runs by itself, without the help of the C library. The module can call printk because, after insmod has loaded it, the module is linked to the kernel and can access the kernel's public symbols (functions and variables, as detailed in the next section). The string KERN_ALERT is the priority of the message.[1] We've specified a high priority in this module, because a message with the default priority might not show up anywhere useful, depending on the kernel version you are running, the version of the klogd daemon, and your configuration. You can ignore this issue for now; we explain it in Chapter 4. printk 函数在 Linux 内核中定义并可供模块使用; 它的行为类似于标准 C 库函数 printf。 内核需要自己的打印功能,因为它自己运行,无需 C 库的帮助。 该模块可以调用 printk,因为在 insmod 加载它之后,该模块链接到内核并且可以访问内核的公共符号(函数和变量,将在下一节中详细介绍)。 字符串 KERN_ALERT 是消息的优先级。[1] 我们在这个模块中指定了一个高优先级,因为默认优先级的消息可能不会显示在任何有用的地方,这取决于您运行的内核版本、klogd 守护程序的版本和您的配置。 你现在可以忽略这个问题; 我们将在第 4 章中解释它。
You can test the module with the insmod and rmmod utilities, as shown below. Note that only the superuser can load and unload a module. 您可以使用 insmod 和 rmmod 实用程序测试模块,如下所示。 请注意,只有超级用户才能加载和卸载模块。
% make
make[1]: Entering directory `/usr/src/linux-2.6.10'
CC [M] /home/ldd3/src/misc-modules/hello.o
Building modules, stage 2.
MODPOST
CC /home/ldd3/src/misc-modules/hello.mod.o
LD [M] /home/ldd3/src/misc-modules/hello.ko
make[1]: Leaving directory `/usr/src/linux-2.6.10'
% su
root# insmod ./hello.ko
Hello, world
root# rmmod hello
Goodbye cruel world
root#
Please note once again that, for the above sequence of commands to work, you must have a properly configured and built kernel tree in a place where the makefile is able to find it (/usr/src/linux-2.6.10 in the example shown). We get into the details of how modules are built in Section 2.4. 请再次注意,要使上述命令序列正常工作,您必须在 makefile 能够找到它的位置(示例中为 /usr/src/linux-2.6.10)中正确配置和构建内核树 如图所示)。 我们将在 2.4 节详细介绍如何构建模块。
According to the mechanism your system uses to deliver the message lines, your output may be different. In particular, the previous screen dump was taken from a text console; if you are running insmod and rmmod from a terminal emulator running under the window system, you won't see anything on your screen. The message goes to one of the system log files, such as /var/log/messages (the name of the actual file varies between Linux distributions). The mechanism used to deliver kernel messages is described in Chapter 4. 根据您的系统用于传递消息行的机制,您的输出可能会有所不同。 特别是,之前的屏幕转储是从文本控制台获取的; 如果您从在窗口系统下运行的终端仿真器运行 insmod 和 rmmod,您将不会在屏幕上看到任何内容。 该消息转到系统日志文件之一,例如 /var/log/messages(实际文件的名称因 Linux 发行版而异)。 第 4 章描述了用于传递内核消息的机制。
As you can see, writing a module is not as difficult as you might expect—at least, as long as the module is not required to do anything worthwhile. The hard part is understanding your device and how to maximize performance. We go deeper into modularization throughout this chapter and leave device-specific issues for later chapters. 如您所见,编写一个模块并不像您想象的那么困难——至少,只要该模块不需要做任何有价值的事情。 困难的部分是了解您的设备以及如何最大限度地提高性能。 我们将在本章中深入探讨模块化,并将特定于设备的问题留给后面的章节。