1.配置内核文件
先把linux-2.6.22.6.tar.bz2以及补丁文件linux-2.6.22.6_jz2440.patch上传到服务器解压缩并打补丁,然后在arch/arm/config找到相似的配置文件:s3c2410_defconfig,然后执行make s3c2410_defconfig,最后执行make menuconfig修改配置项
之后编译内核时,执行make uImage。(uImage是个头部,用于让u-boot引导Linux内核vmLinux启动)
2.配置结果
生成.config文件。以配置项CONFIG_DM9000为例,一共有以下几个文件包含他:
①C源码:CONFIG_DM9000(宏定义)
②子目录Makefile:dirvers/net/Makefile,CONFIG_DM9000在③定义,来源于.config
③include/config/auto.conf,被顶层的Makefile包含
④include/linux/autoconf.h
在include/linux/autoconf.h中DM9000被定义为一个宏且值为1,即
#define CONFIG_DM9000 1
注:
a.不管配置项为y或n,在该文件里都把CONFIG_xxx定义为1
b.子目录Makefile:obj -y += xxx.o和obj -m += yyy.o。-y表示xxx.c最后会被编译进内核。-m表示yyy.c最后会被编译为可加载模块(驱动)。
总结:使用命令make uImage会发生
①.config文件被用来创建生成了一个autoconf.h文件,被源代码使用
②.config也被用来创建生成了auto.conf文件,被子目录下的Makefile使用,被顶层Makefile包含
3.分析Makefile
在顶层Makefile中有编译vmLinux的命令:
zImage Image xipImage bootpImage uImage: vmLinux
而vmLinux依赖于:
vmLinux: $(vmLinux-lds) $(vmLinux-init) $(vmLinux-main) $(kallsyms.o) FORCE
这一些文件在顶层Makefile中的
vmlinux-init := $(head-y) $(init-y)
vmlinux-main := $(core-y) $(libs-y) $(drivers-y) $(net-y)
vmlinux-all := $(vmlinux-init) $(vmlinux-main)
vmlinux-lds := arch/$(ARCH)/kernel/vmlinux.lds
①vmlinux-init := $(head-y) $(init-y):
head-y在arch/arm/Makefile里出现:
head-y := arch/arm/kernel/head$(MMUEXT).o arch/arm/kernel/init_task.o
init-y在顶层Makefile里面出现:
init-y := init/
vmlinux-dirs := $(patsubst %/,%,$(filter %/, $(init-y) $(init-m) \
这两条语句执行完之后即为init-y = init/built-in.o,意思是init目录下涉及到的相关格式的文件会被编译为一个init.o文件
②vmlinux-main := $(core-y) $(libs-y) $(drivers-y) $(net-y):
core-y在顶层Makefile里面出现:
core-y := usr/
core-y += kernel/ mm/ fs/ ipc/ security/ crypto/ block/
core-y := $(patsubst %/, %/built-in.o, $(core-y))
执行完这一些命令后core-y = usr/kernel/built-in.o mm/built-in.o fs/built-in.o ipc/built-in.o security/built-in.o crypto/built-in.o block/built-in.o,即这些目录下相关格式的文件都会被编译为built-in.o
libs-y在顶层Makefile里面出现:
libs-y1 := $(patsubst %/, %/lib.a, $(libs-y))
libs-y2 := $(patsubst %/, %/built-in.o, $(libs-y))
libs-y := $(libs-y1) $(libs-y2)
执行完这一些命令之后libs-y = lib/lib.a lib/built-in.o,即这些目录下相关格式的文件都会被编译为built-in.o
drivers-y在顶层Makefile里面出现:
drivers-y := drivers/ sound/
drivers-y := $(patsubst %/, %/built-in.o, $(drivers-y))
执行完这一些命令之后drivers-y = drivers/built-in.o sound/built-in.o,即这些目录下相关格式的文件都会被编译为built-in.o
net-y在顶层Makefile里面出现:
net-y := net/
net-y := $(patsubst %/, %/built-in.o, $(net-y))
执行完这一些命令之后net-y = net/built-in.o,即这些目录下相关格式的文件都会被编译为built-in.o
从以上分析可以知道,Linux内核的原材料就是以上这么多文件。这一些是如何链接的?
是通过这些命令来编译的:
ifdef CONFIG_HEADERS_CHECK
$(Q)$(MAKE) -f $(srctree)/Makefile headers_check
endif
$(call if_changed_rule,vmlinux__)
$(Q)$(MAKE) -f $(srctree)/scripts/Makefile.modpost $@
$(Q)rm -f .old_version
4.内核启动
内核的最终目的:运行应用程序,对于Linux来说应用程序在根文件系统,因此需要挂接根文件系统
从arch/arm/keenel/head.S开始分析:
注:若内核编译完之后太大,可以压缩完之后在前面加一段自解压代码
①判断是否支持该CPU(比如S3C2440)
②判断是否支持该板子(比如JZ2440,由u-boot在启动内核时传入的机器ID)
③建立页表
④使能MMU
⑤跳转到start_kernel,是内核的第一个C函数,会做一系列初始化工作,并且会调用 setup_arch( )、setup_command_line( )解析u-boot传入的启动参数, 而后调用rest_init( ),rest_init( )会调用kernel_init( ),kernel_init( )调用prepare_namespace( ), prepare_namespace( )调用mount_root( ),即挂接根文件系统。
⑥mount_root( )执行完毕之后回到prepare_namespace( ),prepare_namespace( )执行完毕之后回到kernel_init( ), kernel_init( )再调用init_post( ),init_post( ),会打开/dev/console,然后执行应用程序