logo资料库

The Linux Kernel Module Programming Guide 2.6中文版.doc

第1页 / 共98页
第2页 / 共98页
第3页 / 共98页
第4页 / 共98页
第5页 / 共98页
第6页 / 共98页
第7页 / 共98页
第8页 / 共98页
资料共98页,剩余部分请下载后查看
 The Linux Kernel Module Programming Guide
Foreword
1. 作者声明
2. 版本和注意
3. 感谢
4. 译者注
Chapter 1. Introduction
1.1. 什么是内核模块?
1.2. 内核模块是如何被调入内核工作的?
1.2.1. 在开始前
1.2.1.1. 内核模块和内核的版本问题
1.2.1.2. 使用 X带来的问题
1.2.1.3. 编译相关和内核版本相关的问题
Chapter 2. Hello World
2.1. Hello, World (part 1): 最简单的内核模块
2.1.1. 介绍printk()
2.2. 编译内核模块
2.3. Hello World (part 2)
2.4. Hello World (part 3): 关于__init和__exit宏
2.5. Hello World (part 4): 内核模块证书和内核模块文档说明
2.6. 从命令行传递参数给内核模块
2.7. 由多个文件构成的内核模块
2.8. 为已编译的内核编译模块
Chapter 3. Preliminaries
3.1. 内核模块和用户程序的比较
3.1.1. 内核模块是如何开始和结束的
3.1.2. 模块可调用的函数
3.1.3. 用户空间和内核空间
3.1.4. 命名空间
3.1.5. 代码空间
3.1.6. Device Drivers
3.1.6.1. Major and Minor Numbers
Chapter 4. Character Device Files
4.1. 字符设备文件
4.1.1. 关于file_operations结构体
4.1.2. 关于file结构体
4.1.3. 注册一个设备
4.1.4. 注销一个设备
4.1.5. chardev.c
4.1.6. 为多个版本的内核编写内核模块
Chapter 5. The /proc File System
5.1. 关于 /proc 文件系统
Chapter 6. Using /proc For Input
6.1. 使用 /proc 作为输入
Chapter 7. Talking To Device Files
7.1. 与设备文件对话 (writes and IOCTLs)
Chapter 8. System Calls
8.1. 系统调用
Chapter 9. Blocking Processes
9.1. 阻塞进程
9.1.1. Enter Sandman
Chapter 10. Replacing Printks
10.1. 替换printk
10.2. 让你的键盘指示灯闪起来
Chapter 11. Scheduling Tasks
11.1. 任务调度
Chapter 12. Interrupt Handlers
12.1. Interrupt Handlers
12.1.1. Interrupt Handlers
12.1.2. Intel架构中的键盘
Chapter 13. Symmetric Multi Processing
13.1. 对称多线程处理
Chapter 14. Common Pitfalls
14.1. 注意
Appendix A. Changes: 2.0 To 2.2
A.1. 从2.0到2.2的变化
A.1.1. 从2.0到2.2的变化
Appendix B. Where To Go From Here
B.1. 为什么这样写?
Index
Symbols
A
B
C
D
E
F
G
H
I
K
L
M
N
O
P
Q
R
S
T
V
W
Notes
The Linux Kernel Module Programming Guide 2.4 中文 版 The Linux Kernel Module Programming Guide Peter Jay Salzman Michael Burian Ori Pomerantz Copyright © 2001 Peter Jay Salzman The Linux Kernel Module Programming Guide is a free book; you may reproduce and/or modify it under the terms of the Open Software License, version 1.1. You can obtain a copy of this license at http://opensource.org/licenses/osl.php. This book is distributed in the hope it will be useful, but without any warranty, without even the implied warranty of merchantability or fitness for a particular purpose. The author encourages wide distribution of this book for personal or commercial use, provided the above copyright notice remains intact and the method adheres to the provisions of the Open Software License. In summary, you may copy and distribute this book free of charge or for a profit. No explicit permission is required from the author for reproduction of this book in any medium, physical or electronic. Derivative works and translations of this document must be placed under the Open Software License, and the original copyright notice must remain intact. If you have contributed new material to this book, you must make the material and source code available for your revisions. Please make revisions and updates available directly to the document maintainer, Peter Jay Salzman . This will allow for the merging of updates and provide consistent revisions to the Linux community. If you publish or distribute this book commercially, donations, royalties, and/or printed copies are greatly appreciated by the author and the Linux Documentation Project (LDP). Contributing in this way shows your support for free software and the LDP. If you have questions or comments, please contact the address above.
Table of Contents Foreword 1. 作者声明 2. 版本和注意 3. 感谢 4. 译者注 1. Introduction 1.1. 什么是内核模块? 1.2. 内核模块是如何被调入内核工作的? 1.2.1. 在开始前 1.2.1.1. 内核模块和内核的版本问题 1.2.1.2. 使用 X 带来的问题 1.2.1.3. 编译相关和内核版本相关的问题 2. Hello World 2.1. Hello, World (part 1): 最简单的内核模块 2.1.1. 介绍 printk() 2.2. 编译内核模块 2.3. Hello World (part 2) 2.4. Hello World (part 3): 关于__init和__exit宏 2.5. Hello World (part 4): 内核模块证书和内核模块文档说明 2.6. 从命令行传递参数给内核模块 2.7. 由多个文件构成的内核模块 2.8. 为已编译的内核编译模块 3. Preliminaries 3.1. 内核模块和用户程序的比较 3.1.1. 内核模块是如何开始和结束的 3.1.2. 模块可调用的函数 3.1.3. 用户空间和内核空间 3.1.4. 命名空间 3.1.5. 代码空间 3.1.6. Device Drivers 3.1.6.1. Major and Minor Numbers 4. Character Device Files 4.1. 字符设备文件 4.1.1. 关于 file_operations 结构体 4.1.2. 关于 file 结构体 4.1.3. 注册一个设备 4.1.4. 注销一个设备 4.1.5. chardev.c 4.1.6. 为多个版本的内核编写内核模块 5. The /proc File System 5.1. 关于 /proc 文件系统 6. Using /proc For Input
6.1. 使用 /proc 作为输入 7. Talking To Device Files 7.1. 与设备文件对话 (writes and IOCTLs) 8. System Calls 8.1. 系统调用 9. Blocking Processes 9.1. 阻塞进程 9.1.1. Enter Sandman 10. Replacing Printks 10.1. 替换 printk 10.2. 让你的键盘指示灯闪起来 11. Scheduling Tasks 11.1. 任务调度 12. Interrupt Handlers 12.1. Interrupt Handlers 12.1.1. Interrupt Handlers 12.1.2. Intel 架构中的键盘 13. Symmetric Multi Processing 13.1. 对称多线程处理 14. Common Pitfalls 14.1. 注意 A. Changes: 2.0 To 2.2 A.1. 从 2.0 到 2.2 的变化 A.1.1. 从 2.0 到 2.2 的变化 B. Where To Go From Here B.1. 为什么这样写? Index List of Examples 2-1. hello-1.c 2-2. 一个基本的 Makefile 2-3. hello-2.c 2-4. 两个内核模块使用的 Makefile 2-5. hello-3.c 2-6. hello-4.c 2-7. hello-5.c 2-8. start.c 2-9. stop.c 2-10. Makefile 4-1. chardev.c 5-1. procfs.c 6-1. procfs.c 7-1. chardev.c 7-2. chardev.h 7-3. ioctl.c
8-1. syscall.c 9-1. sleep.c 10-1. print_string.c 10-2. kbleds.c 11-1. sched.c 12-1. intrpt.c Foreword 1. 作者声明 《Linux 内核驱动模块编程指南》最初是由 Ori Pomerantz 为 2.2 版本的内核编 写的 ,后来,Ori 将文档维护的任务交给了 Peter Jay Salzman,Peter 完成了 2.4 内核版本文档 的编写,毕竟 Linux 内核驱动模块是一个更新很快的内容。 现在,Peter 也无法腾出足够的 时间来完成 2.6 内核版本文档的编写,目前该 2.6 内核版本的文档由合作者 Michael Burian 完成。 2. 版本和注意 Linux 内核模块是一块不断更新进步的内容,在 LKMPG 上总有关于是否保留还是 历史 版本的争论。Michael 和我最终是决定为每个新的稳定版本内核建立一个 新的文档分支。也 就是说 LKMPG 2.4.x 专注于 2.4 的内核,而 LKMPG 2.6.x 将 专注于 2.6 的内核。我们不会在一 篇文档中提供对旧版本内核的支持,对此感 兴趣的读者应该寻找相关版本的文档分支。 在文档中的绝大部分源代码和讨论都应该适用于其它平台,但我无法提供任何保 证。其中的一个例外就是 Chapter 12, 中断处理该章的源代码和讨论就只适用 于 x86 平台。 3. 感谢 感谢下列人士为此文档提供了他们宝贵的意见。他们是:Ignacio Martin, David Porter, Daniele Paolo,Scarpazza 和 Dimo Velev。
4. 译者注 我,译者,名叫田竞,目前是一名在北京邮电大学就读的通信专业的大学生。 自 高中起我就是 Linux 的爱好者并追随至今。我喜欢 Linux 给我带来的自由,我想 大家也一样。没有人不向往自由。 我 学习内核模块编写时最初阅读的是 Orelly 出版社的使用 2.0 版本的内核的书 籍,但如同我预料的一样, 书中的许多事例由于内核代码的变化而无法使用。 这让想亲自体验内核模块的神秘的我非常苦恼。 我在 Linux 文档计划在上海的 镜像站 ldp.linuxforum.net 上找到了这篇文档。 受原作者 Ori 的鼓励,基于上次完成的 LKMPG 2.4 的,内容有稍许的改变和扩 充。应该是目前最新的了。 翻译的方式有所改变,在基于 LDP 认可的 docbook 格式上翻译,通过 docbook2html 转换为附件中的 html 文档。 由于对 docbook 不是很熟悉,其中的一些标题尚未翻译,而且可能破坏了原有的 tag,导致 html 出现一些错误显示, 但总体来说很少。修改了很多 2.4 中的错别字。 学习并分享学习的过程是我翻译的最终目的。 Chapter 1. Introduction 1.1. 什么是内核模块? 现在,你是不是想编写内核模块。你应该懂得 C 语言,写过一些用户程序, 那 么现在你将要见识一些真实的东西。在这里,你会看到一个野蛮的指针是如何 毁 掉你的文件系统的,一次内核崩溃意味着重启动。 什 么是内核模块?内核模块是一些可以让操作系统内核在需要时载入和执 行 的代码,这同样意味着它可以在不需要时有操作系统卸载。它们扩展了操作系 统 内核的功能却不需要重新启动系统。举例子来说,其中一种内核模块时设备驱 动 程序模块,它们用来让操作系统正确识别,使用安装在系统上的硬件设备。如 果 没有内核模块,我们不得不一次又一次重新编译生成单内核操作系统的内核镜 像来加入新的功能。这还意味着一个臃肿的内核。 1.2. 内核模块是如何被调入内核工作的?
你可以通过执行 lsmod 命令来查看内核已经加载了哪 些内核模块, 该命令通过 读取/proc/modules 文件的内容 来获得所需信息。 这些内核模块是如何被调入内核的?当操作系统内核需要的扩展功能不存 在 时,内核模块管理守护进程 kmod[1]执行 modprobe 去加载内核模 块。两种类型 的参数被传递给 modprobe:  一个内核模块的名字像 softdog 或是 ppp。  通用识别符像 char-major-10-30。 当传递给 modprobe 是通用识别符时,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 应该很清楚的知道默认标准的内核模块存放的位置。所以,当你想要 载入一个内 核模块时,你可以执行: 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 and 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 用 /lib/modules/2.4.?/local 替代搜寻 misc 内核模块的路径。正如你看到的,命令解释器 shell 的元字符也可以使用。 以 path[net]起始的行告诉 modprobe 在目录 ~p/mymodules 搜索网络方面的内 核模块。但是,在 path[net] 指令之前使用的"keep" 指令告诉 modprobe 只是 将该路径添加到标准搜索路径中,而不是像对待 misc 前面那样进行替换。 以 alias 起始的的行使 modprobe 加载 eepro.o 当 kmod 以通用识别符'eth0' 要 求加载相应内核模块时。 你不会发现像"alias block-major-2 floppy"这样的别名行在文件 /etc/modules.conf 因为 modprobe 已经知道在绝大多数系统上安装的标准的设 备的驱动模块。 现在你已经知道内核模块是如何被调入的了。当你想写你自己的依赖于其它模块 的内核模块时, 还有一些内容没有提供。这个相对高级的问题将在以后的章节 中介绍,当我们已经完成前面的学习后。 1.2.1. 在开始前 在我们介绍源代码前,有一些事需要注意。系统彼此之间的不同会导致许多困难。 顺利的编译并且加载你的第一个"hello world"模块有时就会比较困难。但是当 你跨过 这道坎时,后面会顺利的多。 1.2.1.1. 内核模块和内核的版本问题 为某个版本编译的模块将不能被另一个版本的内核加载如果内核中打开了 CONFIG_MODVERSIONS选项。我们暂时不会讨论与此相关的 内容。在我们进入相 关内容前,本文档中的范例可能在该选项打开的情况下无法 工作。但是,目前 绝大多数的发行版是将该选项打开的。所以如果你遇到和版本 相关的错误时, 最好,重新编译一个关闭该选项的内核。 1.2.1.2. 使用 X 带来的问题
强烈建议你在控制台下输入文档中的范例代码,编译然后加载模块,而不是在 X 下。 模块不能像 printf()那 样输出到屏幕,但它们可以 记录信息和警告,当且仅 当你在使用控制台时这些信息才能最终显示在屏幕上。 如果你从 xterm 中 insmod 一个模块,这些日志信息只会记录在你的日志文件中。 除了查看日志文 件你将无法 得到输出信息。想要及时的获得这些日志信息,建议 所有的工作都 在控制台下进行。 1.2.1.3. 编译相关和内核版本相关的问题 Linux 的发行版经常给内核打一些非标准的补丁,这种情况回导致一些问题的发 生。 一个更普遍的问题是一些 Linux 发行版提供的头文件不完整。编译模块时你将需 要非常多 的内核头文件。墨菲法则之一就是那些缺少的头文件恰恰是你最需要 的。 我强烈建议从 Linux 镜像站点下载源代码包,编译新内核并用新内核启动系统来 避免以上 的问题。参阅"Linux Kernel HOWTO"获得详细内容。 具有讽刺意味的是,这也会导致一些问题。gcc 倾向于在缺省的内核源文件路径 (通常是/usr/src/)下寻找源代码文件。这可以通过 gcc 的-I 选项来切换。 Chapter 2. Hello World 2.1. Hello, World (part 1): 最简单的内核模块 当 第一个洞穴程序员在第一台洞穴计算机的墙上上凿写第一个程序时, 这是一 个在羚羊皮上输出`Hello, world'的字符串。罗马的编程书籍上是以 `Salut, Mundi'这样的程序开始的。 我不明白人们为什么要破坏这个传统, 但我认为还 是不明白为好。我们将从编写一系列的`Hello, world'模块开始, 一步步展示 编写内核模块的基础的方方面面。 这可能是一个最简单的模块了。先别急着编译它。我们将在下章模块编译的章节 介绍相关内容。 Example 2-1. hello-1.c
分享到:
收藏