目录, 显示框架, 无框架

第 14 章
Linux 内核源代码


本章节描述了在 Linux 内核源代码中,您应该从哪里开始查找特定的内核函数。

本书的理解并不依赖于您对 'C' 编程语言的了解,也不要求您拥有 Linux 内核源代码。即便如此,查看内核源代码以深入理解 Linux 操作系统仍然是一个非常有益的练习。本章节概述了内核源代码;它们的组织方式以及您可以从哪里开始查找特定的代码。

从哪里获取 Linux 内核源代码

所有主要的 Linux 发行版(Craftworks, Debian,Slackware, Red Hat等等)都包含内核源代码。通常,安装在您的 Linux 系统上的 Linux 内核就是从这些源代码构建的。但由于其本质,这些源代码往往有些过时,因此您可能需要从章节  www-appendix 中提到的网站之一获取最新的源代码。它们保存在ftp://ftp.cs.helsinki.fi以及所有其他镜像站点上。这使得赫尔辛基网站成为最新的,但像 MIT 和 Sunsite 这样的站点也紧随其后。

如果您无法访问网络,有许多 CD-ROM 供应商以非常合理的成本提供世界主要网站的快照。有些甚至提供季度甚至月度更新的订阅服务。您当地的 Linux 用户组也是源代码的一个良好来源。

Linux 内核源代码有一个非常简单的编号系统。任何偶数内核(例如2.0.30)都是稳定、发布的内核,任何奇数内核(例如2.1.42)都是开发内核。本书基于稳定的2.0.30源代码树。开发内核拥有所有最新的功能并支持所有最新的设备。尽管它们可能不稳定,这可能不是您想要的,但 Linux 社区尝试最新的内核非常重要。这样,它们会为整个社区进行测试。请记住,如果您尝试非生产内核,始终值得彻底备份您的系统。

内核源代码的更改以patch文件形式分发。patch实用程序用于将一系列编辑应用于一组源文件。因此,例如,如果您有 2.0.29 内核源代码树,并且您想要移动到 2.0.30 源代码树,您将获得 2.0.30 patch 文件并将补丁(编辑)应用于该源代码树

$ cd /usr/src/linux
$ patch -p1 < patch-2.0.30

这节省了复制整个源代码树,尤其是在慢速串行连接上。内核补丁(官方和非官方)的一个良好来源是http://www.linuxhq.com网站。

内核源代码是如何组织的

在源代码树的顶层/usr/src/linux您将看到许多目录

arch
这个arch子目录包含所有架构特定的内核代码。它有更深的子目录,每个支持的架构一个,例如i386alpha.
include
这个include子目录包含构建内核代码所需的大多数头文件。它也有更深的子目录,包括每个支持的架构一个。include/asm子目录是指向此架构所需的真实 include 目录的软链接,例如include/asm-i386。要更改架构,您需要编辑内核 makefile 并重新运行 Linux 内核配置程序。
init
此目录包含内核的初始化代码,它是开始查看内核如何工作的一个非常好的地方。
mm
此目录包含所有内存管理代码。架构特定的内存管理代码位于arch/*/mm/,例如arch/i386/mm/fault.c.
drivers
系统所有的设备驱动程序都位于此目录中。它们进一步细分为设备驱动程序的类别,例如block.
ipc
此目录包含内核的进程间通信代码。
modules
这只是一个用于保存已构建模块的目录。
fs
所有文件系统代码。这进一步细分为目录,每个支持的文件系统一个,例如vfatext2.
kernel
主内核代码。同样,架构特定的内核代码位于arch/*/kernel.
net
内核的网络代码。
lib
此目录包含内核的库代码。架构特定的库代码可以在arch/*/lib/.
scripts
此目录包含在配置内核时使用的脚本(例如awktk脚本)。

从哪里开始查找

像 Linux 内核这样的大型复杂程序可能让人望而生畏。它很像一个巨大的线团,看不到线头。查看内核的一部分常常导致查看几个其他相关文件,很快您就忘记了您在寻找什么。接下来的小节为您提示了在源代码树中,对于给定的主题,最佳的查找位置。

系统启动和初始化

在基于 Intel 的系统上,内核在 loadlin.exe 或 LILO 将内核加载到内存并传递控制权后启动。查看arch/i386/kernel/head.S的这部分。Head.S执行一些架构特定的设置,然后跳转到main()例程,位于init/main.c.

内存管理

此代码主要位于mmmm,但架构特定的代码位于arch/*/mm。页面错误处理代码位于mm/memory.c,内存映射和页面缓存代码位于mm/filemap.c。缓冲区缓存实现在mm/buffer.c,交换缓存实现在mm/swapfile.c.

内核

大多数相关的通用代码位于kernelkernelarch/*/kernel,架构特定的代码位于arch/*/kernel。调度器位于kernel/sched.c,fork 代码位于kernel/fork.c。底半部处理代码位于include/linux/interrupt.h数据结构可以在.

include/linux/sched.h

PCIPCI 伪驱动程序位于drivers/pci/pci.c,系统范围的定义位于include/linux/pci.h。每个架构都有一些特定的 PCI BIOS 代码,Alpha AXP 的位于.

arch/alpha/kernel/bios32.c

进程间通信ipc都在ipc中。所有 System V IPC 对象都包含一个ipc_perm数据结构,可以在include/linux/ipc.h中找到。 System V 消息在ipc/msg.c中实现,共享内存在ipc/shm.c中实现,信号量在ipc/sem.c.

中实现。管道在

ipc/pipe.c中断处理内核的中断处理代码几乎都是微处理器(通常是平台)特定的。 Intel 中断处理代码位于arch/i386/kernel/irq.c.

,其定义位于

include/asm-i386/irq.hdrivers设备驱动程序

Linux 内核源代码的大部分行都在其设备驱动程序中。 Linux 的所有设备驱动程序源代码都保存在
drivers中,但这些源代码进一步按类型细分/block块设备驱动程序,例如 ide (在ide.c中)。如果您想查看所有可能包含文件系统的设备是如何初始化的,那么您应该查看device_setup(),位于drivers/block/genhd.c

。它不仅初始化硬盘,还初始化网络,因为您需要网络来挂载
nfs文件系统。块设备包括基于 IDE 和 SCSI 的设备。/char

这是查找基于字符的设备(例如
ttys、串行端口和鼠标)的地方。ide.c/cdromLinux 的所有 CDROM 代码。正是在这里可以找到特殊的 CDROM 设备(例如 Soundblaster CDROM)。请注意,ide CD 驱动程序是ide-cd.cide.cdrivers/block.

,SCSI CD 驱动程序位于
scsi.c。每个架构都有一些特定的 PCI BIOS 代码,Alpha AXP 的位于.

drivers/scsi
/pci

这些是 PCI 伪驱动程序的源代码。是查看 PCI 子系统如何映射和初始化的好地方。 Alpha AXP  PCI 修复代码也值得在
/scsi中查看。这是查找所有 SCSI 代码以及 Linux 支持的 scsi 设备的所有驱动程序的地方。.

/net
这是查找网络设备驱动程序的地方,例如 DECChip 21040 PCI 以太网驱动程序,它位于

tulip.c

/sound这是所有声卡驱动程序所在的位置。文件系统的源代码EXT2文件系统都在fs/ext2/目录中,数据结构定义位于include/linux/ext2_fs_sb.h。虚拟文件系统数据结构在include/linux/fs.hmm/filemap.c中描述,代码位于fs/*fs/buffer.c以及

update

内核守护程序。net网络网络代码保存在net中,大多数头文件位于include/net中。 BSD 套接字代码位于net/socket.c,IP 版本 4 INET 套接字代码位于net/ipv4/af_inet.c中。通用协议支持代码(包括sk_buff处理例程)位于net/core中,TCP/IP 网络代码位于.

net/ipv4

中。网络设备驱动程序位于modulesdrivers/net模块内核模块代码部分位于内核中,部分位于modules包中。内核代码都在kernel/modules.c中,数据结构和内核守护进程kerneld消息位于include/linux/module.hinclude/linux/kerneld.h.


中。您可能想要查看
ELF
对象文件的结构,位于