It’s almost time to begin programming. This chapter introduces all the essential concepts about modules and kernel programming. In these few pages, we build and run a complete (if relatively useless) module, and look at some of the basic code shared by all modules. Developing such expertise is an essential foundation for any kind of modularized driver. To avoid throwing in too many concepts at once, this chapter talks only about modules, without referring to any specific device class. All the kernel items (functions, variables, header files, and macros) that are introduced here are described in a reference section at the end of the chapter.
很快就要开始编程了。本章将介绍关于模块和内核编程的所有基本概念。在这短短几页内容中,我们将构建并运行一个完整的(尽管相对来说没什么实际用处)模块,并了解所有模块共有的一些基础代码。掌握这些知识是开发任何类型模块化驱动程序的重要基础。为了避免一次性引入过多概念,本章仅讨论模块相关内容,不涉及任何特定的设备类别。
本章介绍的所有内核元素(函数、变量、头文件和宏)都将在本章末尾的参考部分进行描述。
Setting Up Your Test System
Starting with this chapter, we present example modules to demonstrate programming concepts. (All of these examples are available on O’Reilly’s FTP site, as explained in Chapter 1.) Building, loading, and modifying these examples are a good way to improve your understanding of how drivers work and interact with the kernel.
从本章开始,我们将通过示例模块来讲解编程概念(所有示例均可在奥莱利(O’Reilly)的 FTP 站点获取,具体说明见第 1 章)。对这些示例进行编译、加载和修改,是深入理解驱动程序如何工作、以及如何与内核交互的有效方法。
The example modules should work with almost any 2.6.x kernel, including those provided by distribution vendors. However, we recommend that you obtain a “mainline” kernel directly from the kernel.org mirror network, and install it on your system. Vendor kernels can be heavily patched and divergent from the mainline; at times, vendor patches can change the kernel API as seen by device drivers. If you are writing a driver that must work on a particular distribution, you will certainly want to build and test against the relevant kernels. But, for the purpose of learning about driver writing, a standard kernel is best.
这些示例模块几乎适用于所有 2.6.x 版本的内核,包括各发行版厂商提供的内核。不过,我们建议你直接从 kernel.org 镜像网络获取 “主线” 内核,并将其安装到你的系统中。厂商提供的内核可能经过大量补丁修改,与主线内核存在差异;有时,厂商的补丁还可能改变设备驱动所面对的内核 API。如果你正在编写必须在特定发行版上运行的驱动程序,那么显然需要针对相关内核进行编译和测试。但就学习驱动程序编写而言,标准内核是最佳选择。
Regardless of the origin of your kernel, building modules for 2.6.x requires that you have a configured and built kernel tree on your system. This requirement is a change from previous versions of the kernel, where a current set of header files was suffi-cient. 2.6 modules are linked against object files found in the kernel source tree; the result is a more robust module loader, but also the requirement that those object files be available. So your first order of business is to come up with a kernel source tree(either from the kernel.org network or your distributor’s kernel source package), build a new kernel, and install it on your system. For reasons we’ll see later, life is
generally easiest if you are actually running the target kernel when you build your modules, though this is not required.
无论你的内核来自何处,为 2.6.x 版本内核编译模块都要求你的系统上有一个已配置并编译好的内核源码树。这与早期版本的内核不同,在早期版本中,只需有一套当前的头文件就足够了。2.6 版本的模块要与内核源码树中的目标文件进行链接,这样做的结果是模块加载器更加健壮,但同时也要求这些目标文件必须可用。因此,你的首要任务是获取一个内核源码树(可以来自 kernel.org 网络,也可以是发行商提供的内核源码包),编译一个新内核,并将其安装到你的系统中。出于我们后面会讲到的原因,通常来说,在编译模块时如果实际运行的就是目标内核,事情会简单很多,不过这并非强制要求。
So, if you do not yet have a suitable system with a configured and built kernel source tree on disk, now would be a good time to set that up. We’ll wait. Once that task is taken care of, you’ll be ready to start playing with kernel modules.
因此,如果你目前还没有一个合适的系统,磁盘上也未准备好已配置且编译完成的内核源码树,那么现在就是搭建它的最佳时机。我们会在此处稍作停留,等你完成这一步。一旦这项工作处理完毕,你就可以开始尝试操作内核模块了。
The Hello World Module
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” 模块:
补充说明:
- kernel modules:即 “内核模块”,是一种可以动态加载到操作系统内核中、用于扩展内核功能的代码片段,无需重新编译整个内核,常见于 Linux 等操作系统的开发中。
- “hello world” example:“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.* 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 表示消息的优先级。在本模块中,我们指定了较高的优先级,因为默认优先级的消息可能不会显示在任何有用的地方,这取决于你所运行的内核版本、klogd 守护进程的版本以及相关配置。目前你可以暂时忽略这个问题,我们会在第 4 章中对其进行解释。
4866

被折叠的 条评论
为什么被折叠?



