Linux内核源代码阅读
阅读原文时间:2021年04月20日阅读:1

这里提到的方式是: windows + source insight 

Source Insight :  可以在CSDN上下载,如: http://download.csdn.net/detail/wwdlk/4695235#comment

关于win7下使用source insight,没有Courier字体的解决方法,请参考:

http://hi.baidu.com/raoxj/item/0e3a3a3b2461c5be134b14fa

关于代码目录,可以参考: http://www.chinabyte.com/biz/cbfwq/345/2617345.shtml

    随着linux的逐步普及,现在有不少人对于Linux的安装及设置已经比较熟悉了。

与Linux 的蓬勃发展相适应,想深入了解Linux的也越来越多。而要想深入了解

Linux,就需要阅读和分析linux内核的源代码。

  Linux的内核源代码可以从很多途径得到。一般来讲,在安装的linux系统下,

/usr/src/linux目录下的东西就是内核源代码。另外还可以从互连网上下载,

解压缩后文件一般也都位于linux目录下。内核源代码有很多版本,目前最新

的稳定版是2.2.14。

  许多人对于阅读Linux内核有一种恐惧感,其实大可不必。当然,象Linux

内核这样大而复杂的系统代码,阅读起来确实有很多困难,但是也不象想象的

那么高不可攀。只要有恒心,困难都是可以克服的。也不用担心水平不够的

问题,事实上,有很多事情我们不都是从不会到会,边干边学的吗?

  任何事情做起来都需要有方法和工具。正确的方法可以指导工作,良好的

工具可以事半功倍。对于Linux 内核源代码的阅读也同样如此。下面我就把自己

阅读内核源代码的一点经验介绍一下,最后介绍Window平台下的一种阅读工具。

  对于源代码的阅读,要想比较顺利,事先最好对源代码的知识背景有一定的

了解。对于linux内核源代码来讲,我认为,基本要求是:

1、操作系统的基本知识;

2、对C语言比较熟悉,最好要有汇编语言的知识和GNU C对标准C的扩展的知识的了解。

另外在阅读之前,还应该知道Linux内核源代码的整体分布情况。

     我们知道现代的操作系统一般由进程管理、内存管理、文件系统、驱动程序、网络等

组成。看一下Linux内核源代码就可看出,各个目录大致对应了这些方面。Linux内核源代码

的组成如下(假设相对于linux目录):

  arch 这个子目录包含了此核心源代码所支持的硬件体系结构相关的核心代码。如对于X86平台就是i386。

  include 这个目录包括了核心的大多数include文件。另外对于每种支持的体系结构分别有一个子目录。

  init 此目录包含核心启动代码。

  mm 此目录包含了所有的内存管理代码。与具体硬件体系结构相关的内存管理代码位于arch/*/mm目录下,

如对应于X86的就是arch/i386/mm/fault.c 。

  drivers 系统中所有的设备驱动都位于此目录中。它又进一步划分成几类设备驱动,每一种也有对应

的子目录,如声卡的驱动对应于drivers/sound。

  ipc 此目录包含了核心的进程间通讯代码。

  modules 此目录包含已建好可动态加载的模块

  fs Linux支持的文件系统代码。不同的文件系统有不同的子目录对应,如ext2文件系统对应的就是ext2子目录。

  kernel 主要核心代码。同时与处理器结构相关代码都放在arch/*/kernel目录下。

  net 核心的网络部分代码。里面的每个子目录对应于网络的一个方面。

  lib 此目录包含了核心的库代码。与处理器结构相关库代码被放在arch/*/lib/目录下。

  scripts此目录包含用于配置核心的脚本文件。

  Documentation 此目录是一些文档,起参考作用。

  清楚了源代码的结构组成后就可以着手阅读。对于阅读方法或者说顺序,有所谓的纵向

与横向之分。所谓纵向就是顺着程序的执行顺序逐步进行;所谓横向,就是分模块进行。其实

他们之间不是绝对的,而是经常结合在一起进行。对于Linux源代码来讲,启动的代码就可以

顺着linux的启动顺序一步一步来,它的大致流程如下(以X86平台为例):

  ./larch/i386/boot/bootSect.S-->./larch/i386/boot/setup.S-->./larch/i386/kernel/head.S

-->./init/main.c中的start_kernel()。而对于象内存管理等部分,则可以单独拿出来进行阅读分析。

我的体会是:开始最好按顺序阅读启动代码,然后进行专题阅读,如进程部分,内存管理部分等。

在每个功能函数内部应该一步步来。实际上这是一个反复的过程,不可能读一遍就理解。

  俗话说:“工欲善其事,必先利其器”。 阅读象Linux核心代码这样的复杂程序令人望而生畏。

它象一个越滚越大的雪球,阅读核心某个部分经常要用到好几个其他的相关文件,不久你将会忘记

你原来在干什么。所以没有一个好的工具是不行的。由于大部分爱好者对于Window平台比较熟悉,

并且还是常用Window系列平台,所以在此我介绍一个Window下的一个工具软件:Source Insight。

这是一个有30天免费期的软件,可以从www.sourcedyn.com下载。安装非常简单,和别的安装一样,

双击安装文件名,然后按提示进行就可以了。安装完成后,就可启动该程序。这个软件使用起来

非常简单,是一个阅读源代码的好工具。它的使用简单介绍如下:先选择Project菜单下的new,

新建一个工程,输入工程名,接着要求你把欲读的源代码加入(可以整个目录加)后,该软件就分析

你所加的源代码。分析完后,就可以进行阅读了。对于打开的阅读文件,如果想看某一变量的定义,

先把光标定位于该变量,然后点击工具条上的相应选项,该变量的定义就显示出来。对于函数的定义

与实现也可以同样操作。别的功能在这里就不说了,有兴趣的朋友可以装一个Source Insight,那样

你阅读源代码的效率会有很大提高的。怎么样,试试吧!

另外,请参考: http://www.linuxidc.com/Linux/2011-04/34241.htm

像Linux内核这样庞大而复杂的程序看起来确实让人望而生畏,它象一个很大的球,没有起点

和终点。在读源代码的过程中,你会遇到这样的情况,当读到内核的某一部分时又会涉及到

其它更多的文件,当返回到原来的地方想继续往下读时,又忘了原来读的内容。在internet上,

很多人为此付出了很大的努力,制作出了源代码导航器,这为源代码阅读提供了良好的条件,

下面给出阅读源代码的一些线索。

1. 系统的启动和初始化

在基于Intel的系统上,当 loadlin.exe 或 LILO把内核装入到内存并把控制权传递给内核时,

内核开始启动。关于这一部分,看arch/i386/kernel/head.S ,head.S进行特定结构的设置,

然后跳转到init/main.c的main()例程。

2. 内存管理

内存管理的代码主要在/mm,但特定结构的代码在archkernel,调度程序在kernel/sched.c,

fork的代码在kernel/fork.c,task_struct 数据结构在 include/linux/sched.h中。

4.  PCI

PCI 伪驱动程序在 drivers/pci/pci.c ,其定义在include/linux/pci.h。每一种结构都有一些特定

的 PCI BIOS 代码, Intel的在arch/alpha/kernel/bios32.c。

5.  进程间通信

所有System V IPC 对象权限都包含在 ipc_perm 数据结构中,这可以在  include/linux/ipc.h中

找到。 System V 消息是在 ipc/msg.c中实现, 共享内存在 ipc/shm.c中,信号量在  ipc/sem.c中,

管道在 ipc/pipe.c中实现。

6. 中断处理

内核的中断处理代码是几乎所有的微处理器所特有的。中断处理代码在  arch/i386/kernel/irq.c中,

其定义子在 include/asm-i386/irq.h中。

7. 设备驱动程序

Linux内核源代码的很多行是设备驱动程序。Linux设备驱动程序的所有源代码都保存在/driver,

根据类型可进一步划分为:

/block

块设备驱动程序如ide(在ide.c)。如果你想看包含文件系统的所有设备是如何被初始化的,

www.linuxidc.com你应当看drivers/block/genhd.c中的device_setup(),device_setup()

不仅初始化了硬盘,当一个网络安装nfs文件系统时,它也初始化网络。块设备包含了

基于IDE和SCSI的设备。

/char

这是看字符设备(如tty,串口及鼠标等)驱动程序的地方。

/cdrom

Linux的所有CDROM代码都在这儿,如在这儿可以找到Soundblaster CDROM的驱动程序。

注意ide CD的驱动程序是 ide-cd.c,放在drivers/block,SCSI CD的驱动程序是scsi.c,放在drivers/scsi。

/pci

这是PCI伪驱动程序的源代码,在这里可以看到PCI子系统是如何被映射和初始化的。

/scsi

在这里可以找到所有的SCSI代码及Linux所支持的scsi设备的所有设备驱动程序。

/net

在这里可以找到网络设备驱动程序,如DECChip 21040 PCI 以太网驱动程序在tulip.c中。

/sound

这是所有声卡驱动程序的所在地。

8. 文件系统

EXT2 文件系统的源代码全部在  fs/ext2/ 目录下,而其数据结构的定义在  include/linux/ext2_fs.h, 

ext2_fs_i.h 及 ext2_fs_sb.h中。 虚拟文件系统的数据结构在include/linux/fs.h中描述,而代码是在

fs/*中。 缓冲区高速缓存与更新内核的守护进程的实现是在 fs/buffer.c中 。

8. 网络

网络代码保存在/net中,大部分的include文件在include/net下,BSD套节口代码在net/socket.c中,

IP 第4版本的套节口代码在net/ipv4/af_inet.c。一般的协议支持代码(包括sk_buff 处理例程)在

net/core下,TCP/IP联网代码在net/ipv4下,网络设备驱动程序在/drivers/net下。

9. 模块

内核模块的代码部分在内核中,部分在模块包中,前者全部在kernel/modules.c中,而数据结构

和内核守护进程kerneld的信息分别在include/linux/module.h和include/linux/kerneld.h 中。如果你

想看ELF目标文件的结构,它位于include/linux/elf.h中。

值得推荐的还有http://blog.sina.com.cn/s/blog_4aa3d81a010007aj.html (列举知识点)

Linux 源代码阅读知识点及要求
说明:1、本次源代码阅读,以Linux 最新的稳定版本(2.6)为主;
2、源代码下载地址:
在官方站点 www.kernel.org 上最新稳定版本是 2.6.13.2;
在清华的 ftp 上随时都可以下载到:
ftp.tsinghua.edu.cn/mirror/kernel.org/linux/kernel/v2.6/
3、源代码阅读辅助工具:
在Windows 环境下推荐SourceInsight3.5
在Linux 环境下推荐SourceNavigator 5
这两个软件都已经上传课程论坛
4、参考书目:
《深入理解Linux 内核》,陈莉君,冯锐、牛欣源译,中国电力出版社
《Linux 内核源代码情境分析》,毛德操,胡希明著,湖南大学出版社
该书的电子稿大家可以在课程论坛上下载
(这些大多是针对2.4 及以前的版本,所以关于2.6 版本的新特色,同
学们还得自己多查阅一些新的资料)
5、本文对知识点的要求中,凡是前面带“***”的要求都可能被列为考点,在期末
考试中进行考查,所以请大家一定要认真读懂。
6、第四部分“设备管理”是选读部分,感兴趣有精力的同学可以多读一读,这部分
中标注“**”的知识点,可能作为考试的附加题出现。
7、Linux 源代码阅读仍然以4 人小组为单位进行,建议大家合理分工阅读,积极交
流讨论。后半学期鼓励有心得的小组做相关的presentation,自由报名。
一、内存管理
1. 地址映射和物理内存管理
[要求]
(1)***理解x86 的地址映射过程
(2)***理解内核符号的线性地址和物理地址的相互转换
(3)***理解物理页面的管理,内核维护描述物理页面的数据结构的作用和意义
(4)***理解内核对全局变量page 或map 的初始化,理解物理页面大致的分配情况
[代码]
(1)\linux\mm\mmap.c
精读:vma 相关的管理函数;
泛读:***L 数据结构相关函数;
(2)\linux\mm\memory.c
精读:页表和页目录操作函数,含有许多体系结构方面的知识;
(3)\linux\mm\page_io.c 和\linux\mm\page_alloc.c
精读:物理页面的分配过程
(4)\linux\mm\swap.c
精读:页面换入换出的管理,注意对页表页目录的操作,及其意义
泛读:换入换出的策略和算法;
2. 用户地址空间管理
[要求]
(1)***理解内核中维护的代表用户地址空间的数据结构
(2)***掌握用户地址空间的扩展和页故障的处理(结合物理页面映射)
(3)***理解用户地址空间共享
(4)***理解内核中对堆空间的管理,slab 块的管理(单纯的内存管理,不涉及系统
其它部分)
(5)***理解fork 系统调用时对用户地址空间的管理
[代码]
(1)\linux\mm\slab.c
精读:内核堆空间的管理函数;
泛读:涉及多处理器的部分;
(2)\linux\i386\mm\fault.c
精读:do_page_fault 函数,注意对页表以及vma 的操作;
二、Linux 中断、系统调用、时钟、定时器
1、X86CPU 对中断的硬件支持
【要求】
(1)了解X86CPU 保护模式下中断的响应机制
(2)***中断门的概念与作用
(3)***系统响应中断时,中断服务程序入口的寻址机制
【代码】无代码阅读要求,但要查阅相关资料,掌握原理性知识,这是阅读代码必需的
背景知识
2、中断向量表IDT 的初始化
【要求】
其中针对每个中断向量的一个结构数组irq_desc[ ]的设置和处理可以多了解。
(1)了解系统初始化中断机制的时机,这可能需要查阅相关资料或者阅读系统初
始化相关的代码;
(2)了解中断描述表idt_table 的表项是如何被设置的
【代码】
(1)arch/i386/kernel/i8259.c
精读:init_IRQ();
泛读:IRQ(x, y);IRQLIST_16(x);
Challenge:BULID_16_IRQS(x);BULID_IRQ(nr);
(2)arch/i386/kernel/traps.c
泛读:trap_int( ); set_intr_gate(…);_set_gate(…);
(3)include/asm-i386/irq.h
里面提供了一些相关常量的宏定义
3、中断请求队列的初始化
【要求】
了解中断服务程序是如何登记到系统中并进行相关初始化的。
(1)理解中断请求队列的意义,理解irq_desc[ ]结构中主要字段的含义
(2)***中断服务程序是通过怎样的途径挂入到中断请求队列中的
(3)区分“中断请求号”和中断向量的概念
【代码】
(1) include/linux/irq.h
泛读:数据结构irq_desc[]
(2)include/linux/interrupt.h
泛读:数据结构struct irqaction
(3)arch/i386/kernel/i8259.c
精读:init_ISA_irqs( );
(4)arch/i386/kernel/irq.c
精读:request_irq(); setup_irq()
4、中断的响应和服务
【要求】
(1)***公共响应入口common_interrupt 需要完成的工作
(2)了解中断响应前后系统堆栈的变化
(2)***系统如何根据中断号找到并执行响应的中断服务程序
(3)***Linux 中为何引入Bottom Half 机制
(4)中断返回时操作系统需要做哪些相关工作
【代码】
(1)include/asm-i386/hw_irq.h
精读:common_interrupt();
(2)arch/i386/kernel/irq.c
精读:do_irq(); handle_IRQ_event( );
(3)arch/i386/kernel/entry.S
精读:ret_from_intr
5、Bottom half
【要求】
(1)***理解Linux 引入Bottom half 机制的意义;
(2)比较Linux 2.6 版本和Linux 2.4 版本在该机制上的异同
(3)了解Bottom half 机制的框架和执行特点;
【代码】
(1)kernel/softirq.c
泛读:softirq_init();
(2)include/linux/interrupt.h
泛读:mark_bh(int nr)
(3)kernel/softirq.c
泛读:do_softirq();
6、时钟中断
【要求】
(1)***明确区分“系统时钟”、“实时时钟”、“jiffies”的概念;
(2)系统时钟的初始化;
(3)时钟中断的处理
(4)***定时器(timer)的实现
【代码】
(1)include/linux/time.h
了解相关的数据结构
(2)include/asm-386/param.h
了解相关的数据结构
(3)arch/i386/kernel/time.c
精读:time_init()
(4)kernel/timer.c
精读:do_timer( )
7、系统调用
【要求】
(1)系统调用的处理流过程是怎样的(包括响应、处理和返回)
(2)***与普通函数调用的区别
(3)***系统调用与中断的异同
【代码】
arch/i386/kernel/entry.S
精读system_call( );ret_from_sys_call();
三、进程部分
1. Linux 中的进程
[要求]
(1)了解进程和轻量级进程的概念和区别
(2)***掌握进程描述符
(3)***了解该结构中重点字段的含义
[代码]
文件名:sched.h
精读:进程描述符task_struct
2.Linux 中进程的创建
[要求]
(1)***掌握Linux 中使用该创建进程的过程
(2)***掌握相关的数据结构和相关的系统调用
(3)***了解其执行的内存变动和硬件的相关变化
[代码]
(1)文件名:fork.c
精读:do_fork()
泛读:get_pid();copy_files();copy_fs();copy_sighand();copy_mm()
(2)文件名:mm/memory.c
精读:copy_page_range()
(3)文件名:arch/i386/kernel/process.c
泛读:copy_segments();copy_thread()
3.Linux 中进程的转变
[要求]
(1)***了解通过一个新的进程覆盖原来的内存空间实现进程转变的过程
(2)***掌握其相关的数据结构和相关的系统调用
(3)了解其执行的内存的变动以及硬件相关的变化
[代码]
文件名:exec.c
精读do_execve()
泛读open_exec();search_binary_handler
4.进程的撤销
[要求]
***掌握进程是如何撤销的,比如撤销的时机,撤销的过程等
[代码]
文件名:exit.c
精读:do_exit()
泛读:sem_exit();exit_notify();forget_original_parent
5.进程的调度
[要求]
(1)***掌握Linux 进程的调度时机
(2)***掌握Linux 进程的调度策略
[代码]
文件名:sched.c
精读 :schedule();
泛读: sched.c 中的其他进程
6.进程间通信-管道、共享内存、信号、消息队列
[要求] 此部分四人一组,每人从这四种进程间通信方式选一种进行阅读
(1)***了解使用管道进行进程间通信的方法,掌握管道的创建和读写过程等
(2)***了解使用共享内存进行进程间通信的方法,掌握共享内存区的创建方法,以
及对共享内存区的控制和管理
(3)*** 了解使用信号进行进程间通信的方法,掌握信号的发送,接收和处理过程
(4)***了解使用消息队列进行进程间通信的方法,掌握消息缓冲区、消息结构、消
息队列结构,以及相关的系统调用
[代码]
(1)文件名:pipe.c
精读:do_pipe();read_pipe();write_pipe()
泛读:该文件中其余函数
(2)文件名:shm.c
精读:数据结构shmget();shmat();shmctl()
泛读:shm.c 中其他函数
(3)文件名:signal.c
精读:signal();sigaction();pause();alarm();kill()
泛读:signal.c 中其他的函数
(4)文件名:msg.c
精读:msgget();msgsnd();msgsnd()
泛读:文件中其他函数
7.进程间通信-信号量
[要求]
(1)***了解使用信号量进行进程间通信的方法
(2)***掌握信号量的创建方法、信号量的操作以及对信号量的控制和管理
[代码]
sem.c
精读:semget();semop();semctl()
泛读:sem.c 中其他函数
四、设备管理(选读)
1. 层次设备驱动实例
[要求]
(1)了解tty 设备的高级操作
(2)以tty 设备为例,理解内核意义下的设备和硬件设备的区别
(3)理解高级设备与低级设备的分工,高级设备与低级设备之间的控制权转移
[代码]
(1)\linux\drivers\char\console.c
精读:内核堆空间的管理函数;
泛读:涉及多处理器的部分;
(2)\linux\drivers\char\keyboard.c
精读:do_page_fault 函数,注意对页表以及vma 的操作;
(3)\linux\drivers\char\tty_io.c 和\linux\drivers\char\tty_ioctl.c
精读:tty 设备的高级操作,注意与其它设备的联系,以及提供的机制
泛读:操作过于细节的部分;
2. 设备文件系统devfs
[要求]
(1)**掌握用户态下通过devfs 访问设备
(2)理解devfs 挂载到文件系统中的过程,以及遍历devfs 定位目标设备的过程
(3)**理解devfs 与一般的文件系统的区别
[代码]
(1)\linux\fs\devfs\base.c 和\linux\fs\devfs\util.c
精读:设备文件系统devfs 的管理;注意devfs 与普通fs 在管理上的差别
3. 磁盘存储管理
[要求]
(1)**理解磁盘物理结构,分区信息和超级块的位置,及其内容
(2)**理解加电启动时BIOS 的默认行为,以及对磁盘的操作
(3)理解磁盘逻辑结构,文件操作转化为对磁盘的操作的过程,磁盘操作涉及的DMA
机制
[代码]
(1)\linux\kernel\dma.c
泛读:注意DMA 的工作原理,将原理与代码相互对照理解
(2)\linux\drivers\ide\hd.c
精读:硬件中断的分派和处理;
泛读:硬盘的底层操作;
(3)\linux\drivers\ide\ide_dma.c 和\linux\drivers\ide\ide_disk.c
泛读:IDE 硬盘的相关操作;硬盘DMA 相关操作;将原理与编程实践结合