当今,我们身边如此多的服务器,工作站都运行着linux,因此也有不少的朋友想了解linux内的核心机理。但是由于kernel过于庞大,以致让一些朋友望而却步。(我在大二的时候也有过此经历,当时看到一些人在看kernel,自己也想进去一探究竟,但进去没多久就乱了头绪,从而转去看uboot源码)。今天我就以我个人的视角来展示kernel的结构图(先申明下,这里并不是讲目录结构图的,因为从目录的名字就知道里面放的是何种文件,我如果讲目录结构的话,相信很多同学会开挂骂我了),以及kernel是如何生成的,以给大家作为一种小借鉴吧!(在这以arm为例子 Linux kernel并不是一个何方神圣,说简单点的话,它无非是一个源码树组织而成的一个大的源代码,通过编译器编译后的一个可执行文件。既然是由一个源码树过来的,那么我们就进入源码树去一探究竟吧!(在此我给大家推荐一本我感觉比较好的书吧,书名:《Embedded.Linux.Primer》,建议大家看英文原版的,用中文翻译过来的书里面,有些内容虽然不能说它写错了,但它也没有把明确的作者意思完完全全的表达出来,让人看起来别扭,作为IT领域的人,我们也应该多看看英文资料!)
要想了解kernel的整体结构,我建议大家最好有关于makefile的知识,因为像kernel这些庞大的工程用makefile来管理,控制整个编译过程很方便的。其实如果对makefile非常熟悉的话,可以完全无视此博文,直接看makefile就能全然得知整个kernel源码树结构。因此先学下makefile的相关知识为好,因为自己掌握了
makefile之后,就不用信赖他人了,不用别人说是这样你就跟着以为是这样,没准人家说错了呢。有适合多处好的方法总比只学一处的好,就比如C++里的类中
的方法一样,所有对象可以共用一个方法,但每个对象的属性值各不相同(感觉这个比喻不合理,先这样吧,意会一下就行)。
下面我们进入kernel的主目录,可以看到有下面的内容:
arch .config crypto firmware .gitignore ipc kernel MAINTAINERS net samples sound virt
block COPYING Documentation fs include Kbuild lib Makefile README scripts tools
certs CREDITS drivers .get_maintainer.ignore init Kconfig .mailmap mm REPORTING-BUGS security usr
(我这是最近下载的linux-4.4-rc4的版本,其它版本的主目录也基本一样,其中。config是我用make menuconfig生成的一个配置文件)。既然makefile是管理整个工程的,那我们第二个要看的当然是Makefile了(哈哈,第一个要看的当然是README了,养成这个好习惯),在Makefile中的起始我们就能看到:
8 # To see a list of typical targets execute "make help"
9 # More info can be located in ./README
没错,看下Makefile当中的help:
1244 help:
1245 @echo 'Cleaning targets:'
1246 @echo ' clean - Remove most generated files but keep the config and'
1247 @echo ' enough build support to build external modules'
1248 @echo ' mrproper - Remove all generated files + config + various backup files'
1249 @echo ' distclean - mrproper + remove editor backup and patch files'
1250 @echo ''
1251 @echo 'Configuration targets:'
1252 @$(MAKE) -f $(srctree)/scripts/kconfig/Makefile help
1253 @echo ''
1254 @echo 'Other generic targets:'
1255 @echo ' all - Build all targets marked with [*]'
1256 @echo '* vmlinux - Build the bare kernel'
1257 @echo '* modules - Build all modules'
1258 @echo ' modules_install - Install all modules to INSTALL_MOD_PATH (default: /)'
1259 @echo ' firmware_install- Install all firmware to INSTALL_FW_PATH'
1260 @echo ' (default: $$(INSTALL_MOD_PATH)/lib/firmware)'
1261 @echo ' dir/ - Build all files in dir and below'
1262 @echo ' dir/file.[oisS] - Build specified target only'
.
.
.
比较多行就不全部罗列出来了,可以看到用make menuconfig来生成一个指示工程编译的配置文件.config。致于这个界面是如何产生的,然后又如何生成.config的,我还是说一下吧:还是看Makefile:
527 config: scripts_basic outputmakefile FORCE
528 $(Q)$(MAKE) $(build)=scripts/kconfig $@
529
530 %config: scripts_basic outputmakefile FORCE
531 $(Q)$(MAKE) $(build)=scripts/kconfig $@
对,是通过.../scripts/kconfig这个脚本来产生的(...代表源码树主目录)。大家会发现主目录下的子目录里都有一个Kconfig,它就是用于给menuconfig来配
置编译信息的。既然这通过它来达到间接配置编译相关指示信息的,那就看看.../Kconfig:
mainmenu "Linux/$ARCH $KERNELVERSION Kernel Configuration"
config SRCARCH
string
option env="SRCARCH"
source "arch/$SRCARCH/Kconfig"
看到source后就进去看.../arch/$SRCARCH/Kconfig文件吧,它会把源码树中的所有要用到的Kconfig全包含进来。包含进来了哪些,大家看Kconfig吧,有好几百
个呢。
上面说了这么多的看似不重要的东西,其实在我看来它们是最要注意的,因为如果连主体结构都不熟悉的话,那你看源码会是一团乱麻,更别提后续修改以及裁剪kernel了。熟悉了整个结构之后,你就知道去哪查看,修改,添加代码。 上面是基于makefile,kconfig来说明是通过什么方法来组织这个庞大的kernel,并达到方便用户进行自主配置编译信息等内容的。下面就说说kernel的生成吧。
既然kernel是操作系统的核心部分,通常的操作系统还都有文件系统等其它部件,这里主要说kernel,文件系统那些就先不提了(况且博主我也还没开始学它呢,大神
看到了的话望提供点学习文件系统的建议哟).好的,开始一起谈论kernel吧,既然kernel在全世界如此火爆,和我们形影不离,android,linux各种发行版的操作系统以及形形色色的servers都在用它,肯定有它特有的功能的。有一点必须明确:一台计算机刚加电启动时运行的并不是kernel,而是bootloader(pc机上通常叫BIOS),bootloader(bios)启动后,再把cpu的执行权传给kernel,kernel得到执行权后再进行一系列初始化,接着挂载根文件系统(root file system),执行一些脚本(scripts,比如你们linux系统下的/etc/init.d,/etc/cron*等这些)来启动一些系统进程(比如用户login程序,以太网初始化等)。既然kernel的执行是位于bootloader(BIOS)之后,那么它是怎么来接管bootloader(BIOS)的执行权呢?进入.../arch/arm/boot/compressed/目录下,看到了一个链接文件了没,名叫vmlinux.lds.S,对真正的kernel的二进制可执行文件vmlinux将会位于这(编译完内核可以看下),编译时你的终端会输出编译信息,通过查看这些信息你可以知道有哪些文件被编译进行内核中,一般会有下面这些:
arch/arm/kernel/head.o
arch/arm/kernel/init-atask.o
init
usr/built-in.o
arch/arm/kernel
arch/arm/mm
arch/arm/common
arch/arm/mach-ixp4xx
arch/arm/nwfpe
kernel
mm
fs
ipc
security
lib/lib.a
arch/arm/lib
lib
drivers
net
接着上面讲kernel在哪接管CPU的执行权的问题,也就是说kernel真正意义上的第一行代码到底在哪,注意:由于kernel是多平台的内核,所以这里讲和真正意义上的
第一行代码是去除了它之前的特定架构特定处理器的初始代码之后的首行代码。kernel真正的第一行代码是位于.../arch/$(SUBARCH)/kernel/head.S,在这里kernel会检测有效的architecture和processor,建立起初始页表入口,同时会使能MMU,然后真正起动kernel本身(跳转到.../init/main.c),说到这个main.c文件,这个文件是我们必须要好好看,好好理解它,通过它来慢慢切入到kernel当中,做到深度理解传说中的kernel。 之前不是一直强调kernel真正意义下的第一行代码吗,下面就来说说为什么吧,由于不同的处理器,一些处理器得先通过相应处理之后才能把CPU执行权交给kernel, 因此不同的架构下,它们还有不同的head.S(位于.../arch/$(SUBARCH)/boot/compressed/),比如power pc下有:head_32.S,head_40x.S,head_44x.S等。bootloader通过这些汇编程序再这把控制权交给kernel,在这的特定架构处理器的head.S程序会对processor进行一些处理,比如进行关中断,使能processor的指令缓存和数据缓存,建立起一个适合C代码运行的环境。大家也可以这样理解,把.../arch/$(SUBARCH)/kernel/head.S之前的操作看作第二个bootloader,它还可以对kernel进行校验,执行kernel的解压(在.../arch/$(SUBARCH)/boot/misc.c中实现此功能,函数为decompress_kernel),和kernel在内存中的重定位。不过有一些架构的处理器可以直接引导kernel,不必进行上面这些过程操作。
第一篇关于kernel的博文就到这里吧,高手们欢迎提出好的建议,以及错误究正,共同学习进步,都凌晨了,大家下回见!