LINUX内核源程序文件组织和内核结构武汉大学计算机学院郑鹏Email:pzheng51@163.com内核源程序文件的组织Linux内核源程序通常都安装在/usr/src/linux下,而且它有一个非常简单的编号约定:任何偶数的内核(第二个数为偶数)都是一个稳定地发行的内核,而任何奇数的内核都是一个开发中的内核。由于Linux内核是一种单内核模式的系统,因此,内核中所有的程序几乎都有紧密的联系,它们之间的依赖和调用关系非常密切。当我们使用tar命令将linux-0.11.tar.gz解开时,内核源代码文件被放到了linux目录中。其中的目录结构为:Linux内核源代码的目录结构Linux内核源代码目录结构1.内核主目录linuxlinux目录是源代码的主目录,其中除了包括所有的14个子目录以外,还含有唯一的一个makefile文件。makefile文件是编译辅助工具make的参数配置文件。make工具软件的主要用途是通过识别哪些文件已被修改过,从而自动地决定在一个含有多个源程序文件的程序系统中哪些文件需要被重新编译。linux目录下的这个makefile文件还嵌套地调用了所有子目录中包含的makefile文件,这样,当linux目录(包括子目录)下的任何文件被修改过时,make都会对其进行重新编译。因此为了编译整个内核所有的源代码文件,只要在linux目录下运行一次make软件即可。2.引导启动程序目录bootboot目录中含有3个汇编语言文件,是内核源代码文件中最先被编译的程序。这3个程序完成的主要功能是当计算机加电时引导内核启动,将内核代码加载到内存中,并做一些进入32位保护运行方式前的系统初始化工作。其中bootsect.s和setup.s程序需要使用as86软件来编译,使用的是as86的汇编语言格式(与微软的类似),而head.s需要用GNUas来编译,使用的是AT&T格式的汇编语言。bootsect.s程序是磁盘引导块程序,编译后会驻留在磁盘的第一个扇区中(引导扇区,0磁道(柱面),0磁头,第1个扇区)。在PC机加电ROMBIOS自检后,将被BIOS加载到内存0x7C00处进行执行。setup.s程序主要用于读取机器的硬件配置参数,并把内核模块system移动到适当的内存位置处。head.s程序会被编译连接在system模块的最前部分,主要进行硬件设备的探测设置和内存管理页面的初始设置工作。3.文件系统目录fs(1)是实现文件系统程序的目录,共包含17个C语言程序。这些程序之间的主要引用关系见下图所示。图中每个方框代表一个文件,从上到下基本按引用关系放置。其中各文件名均略去了后缀.c,虚框中的程序文件不属于文件系统,带箭头的线条表示引用关系,粗线条表示有相互引用关系。3.文件系统目录fs(2)fs目录中各程序中函数之间的引用关系3.文件系统目录fs(3)由图可以看出,该目录中的程序可以划分成四个部分:高速缓冲区管理低层文件操作文件数据访问文件高层函数。对于文件系统,可以将它看成是内存高速缓冲区的扩展部分。所有对文件系统中数据的访问,都需要首先读取到高速缓冲区中。本目录中的程序主要用来管理高速缓冲区中缓冲块的使用分配和块设备上的文件系统。管理高速缓冲区的程序是buffer.c,而其它程序则主要都是用于文件系统管理。3.文件系统目录fs(4)在file_table.c文件中,目前仅定义了一个文件句柄(描述符)结构数组。ioctl.c文件将引用kernel/chr_dev/tty.c中的函数,实现字符设备的io控制功能。exec.c程序主要包含一个执行程序函数do_execve(),它是所有exec()函数簇中的主要函数。fcntl.c程序用于实现文件i/o控制的系统调用函数。read_write.c程序用于实现文件读/写和定位三个系统调用函数。stat.c程序中实现了两个获取文件状态的系统调用函数。open.c程序主要包含实现修改文件属性和创建与关闭文件的系统调用函数。3.文件系统目录fs(5)char_dev.c主要包含字符设备读写函数rw_char()。pipe.c程序中包含管道读写函数和创建管道的系统调用。file_dev.c程序中包含基于i节点和描述符结构的文件读写函数。namei.c程序主要包括文件系统中目录名和文件名的操作函数和系统调用函数。block_dev.c程序包含块数据读和写函数。inode.c程序中包含针对文件系统i节点操作的函数。truncate.c程序用于在删除文件时释放文件所占用的设备数据空间。bitmap.c程序用于处理文件系统中i节点和逻辑数据块的位图。super.c程序中包含对文件系统超级块的处理函数。buffer.c程序主要用于对内存高速缓冲区进行处理。3.文件系统目录fs(6)虚框中的ll_rw_block是块设备的底层读函数,它并不在fs目录中,而是kernel/blk_dev/ll_rw_block.c中的块设备读写驱动函数。放在这里只是让我们清楚的看到,文件系统对于块设备中数据的读写,都需要通过高速缓冲区与块设备的驱动程序(ll_rw_block())来操作进行,文件系统程序集本身并不直接与块设备的驱动程序打交道。在对程序进行注释过程中,我们将另外给出这些文件中各个主要函数之间的调用层次关系。4.头文件主目录include(1)头文件目录中总共有32个.h头文件。其中主目录下有13个,asm子目录中有4个,linux子目录中有10个,sys子目录中有5个。这些头文件各自的功能见如下简述。a.out.ha.out头文件,定义了a.out执行文件格式和一些宏。const.h常数符号头文件,目前仅定义了i节点中i_mode字段的各标志位。ctype.h字符类型头文件。定义了一些有关字符类型判断和转换的宏。errno.h错误号头文件。包含系统中各种出错号。(Linus从minix中引进的)。fcntl.h文件控制头文件。用于文件及其描述符的操作控制常数符号的定义。signal.h信号头文件。定义信号符号常量,信号结构以及信号操作函数原型。4.头文件主目录include(2)stdarg.h标准参数头文件。以宏的形式定义变量参数列表。主要说明了-个类型(va_list)和三个宏(va_start,va_arg和va_end),用于vsprintf、vprintf、vfprintf函数。stddef.h标准定义头文件。定义了NULL,offsetof(TYPE,MEMBER)。string.h字符串头文件。主要定义了一些有关字符串操作的嵌入函数。termios.h终端输入输出函数头文件。主要定义控制异步通信口的终端接口。time.h时间类型头文件。其中最主要定义了tm结构和一些有关时间的函数原形。unistd.hLinux标准头文件。定义了各种符号常数和类型,并申明了各种函数。如定义了__LIBRARY__,则还包括系统调用号和内嵌汇编_syscall0()等。utime.h用户时间头文件。定义了访问和修改时间结构以及utime()原型。体系结构相关头文件子目录include/asm这些头文件主要定义了一些与CPU体系结构密切相关的数据结构、宏函数和变量。共4个文件。asm/io.hio头文件。以宏的嵌入汇编程序形式定义对io端口操作的函数。asm/memory.h内存拷贝头文件。含有memcpy()嵌入式汇编宏函数。asm/segment.h段操作头文件。定义了有关段寄存器操作的嵌入式汇编函数。asm/system.h系统头文件。定义了设置或修改描述符/中断门等的嵌入式汇编宏。Linux内核专用头文件子目录include/linuxlinux/config.h内核配置头文件。定义键盘语言和硬盘类型(HD_TYPE)可选项。linux/fdreg.h软驱头文件。含有软盘控制器参数的一些定义。linux/fs.h文件系统头文件。定义文件表结构(file,buffer_head,m_inode等)。linux/hdreg.h硬盘参数头文件。定义访问硬盘寄存器端口,状态码,分区表等信息。linux/head.hhead头文件,定义了段描述符的简单结构,和几个选择符常量。linux/kernel.h内核头文件。含有一些内核常用函数的原形定义。Linux内核专用头文件子目录include/linuxlinux/mm.h内存管理头文件。含有页面大小定义和一些页面释放函数原型。linux/sched.h调度程序头文件,定义了任务结构task_struct、初始任务0的数据,还有一些有关描述符参数设置和获取的嵌入式汇编函数宏语句。linux/sys.h系统调用头文件。含有72个系统调用C函数处理程序,以'sys_'开头。linux/tty.htty头文件,定义了有关tty_io,串行通信方面的参数、常数。系统专用数据结构子目录include/syssys/stat.h文件状态头文件。含有文件或文件系统状态结构stat{}和常量。sys/times.h定义了进程中运行时间结构tms以及times()函数原型。sys/types.h类型头文件。定义了基本的系统数据类型。sys/utsname.h系统名称结构头文件。sys/wait.h等待调用头文件。定义系统调用wait()核waitpid()及相关常数符号。5.内核初始化程序目录init该目录中仅包含一个文件main.c。用于执行内核所有的初始化工作,然后移到用户模式创建新进程,并在控制台设备上运行shell程序。程序首先根据机器内存的多少对缓冲区内存容量进行分配,如果还设置了要使用虚拟盘,则在缓冲区内存后面也为它留下空间。之后就进行所有硬件的初始化工作,包括人工创建第一个任务(task0),并设置了中断允许标志。在执行从核心态移到用户态之后,系统第一次调用创建进程函数fork(),创建出一个用于运行init()的进程,在该子进程中,系统将进行控制台环境设置,并且在生成一个子进程用来运行shell程序。6.内核程序主目录kernel(1)linux/kernel目录中共包含12个代码文件和一个Makefile文件,另外还有3个子目录。各文件的调用层次关系如下:6.内核程序主目录kernel(2)asm.s程序是用于处理系统硬件异常所引起的中断,对各硬件异常的实际处理程序则是在traps.c文件中,在各个中断处理过程中,将分别调用traps.c中相应的C语言处理函数。exit.c程序主要包括用于处理进程终止的系统调用。包含进程释放、会话(进程组)终止和程序退出处理函数以及杀死进程、终止进程、挂起进程等系统调用函数。fork.c程序给出了sys_fork()系统调用中使用了两个C语言函数:find_empty_process()和copy_process()。mktime.c程序包含一个内核使用的时间函数mktime(),用于计算从1970年1月1日0时起到开机当日的秒数,作为开机秒时间。仅在init/main.c中被调用一次。panic.程序包含一个显示内核出错信息并停机的函数panic()。printk.c程序包含一个内核专用信息显示函数printk()。6.内核程序主目录kernel(3)sched.c程序中包括有关调度的基本函数(sleep_on、wakeup、schedule等)以及一些简单的系统调用函数。另外还有几个与定时相关的软盘操作函数。signal.c程序中包括了有关信号处理的4个系统调用以及一个在对应的中断处理程序中处理信号的函数do_signal()。sys.c程序包括很多系统调用函数,其中有些还没有实现。system_c