linux内核启动流程分析

配置内核的结果是,生成一个.config文件,该文件又自动生成一个include/config/auto.conf和include/linux/autoconf.h,其中后者给C的源代码使用,会包含在C源码代码中;前者被顶层的makefile包含,给子目录的makefile使用。
这一点可以通过查找其中某一项模块来跟踪。

本节:

子目录的makefile;
架构相关的makefile(/arch/arm/makefile);
分析一个makefile,从其命令开始分析,make,make uImage,从顶层makefile开始分析。
分析make uImage命令,该目标uImage在顶层makefile里没有,其位置在arch/arm/makefile,则此makefile会被包含进入顶层makefile中。

auto.conf文件也被顶层makefile包含。

回到目标make uImage,在架构makefile中,uImage是内核加头部,uImage依赖于vmlinux,vmlinux是真正的内核;
我们直接命令make,这执行第一个目标all,all也依赖与vmlinux。那么vmlinux依赖于谁呢?
vmlinux: $(vmlinux-lds) $(vmlinux-init) $(vmlinux-main) $(kallsyms.o) FORCE
以上各部分依赖如下:
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/$(SRCARCH)/kernel/vmlinux.lds
然后,接着分析
head-y:不在顶层makefile,在架构相关makefile中
将上诉依赖一一陈列,再去细细分析可能就会比较繁琐,我们可以通过一一分析makefile去了解文件的连接方式,也可以使用另一种比较实用的方式,直接编译,找出最后一句已执行命令的输出,分析该输出语句。
通过该语句的分析,可以找出:
第一个文件:arch/arm/kernel/head.S
连接脚本:arch/arm/kernel/vmlinux.lds(源码中是vmlinux.lds.S)
文件连接的顺序由命令中.o文件的位置决定 

内核启动流程:
分析makefile的时候我们看到的第一个文件head.S,就是我们分析内核的起始文件!
head.S有两个,一个处于compressed里面:
内核很大,压缩一下,压缩后的代码前加一个自解压代码,因此有一段head.S是在compressed文件夹里。
我们此处暂且只关心真正的head.S。
head.s内核工作:
1.处理uboot传入的数据:机器ID,启动参数;
a.判断是否支持这个CPU;
b.判断是否支持这个单板;
c.建立一级页表;
d.使能mmu
c.跳到start_kernel,(kernel_sabrelite\init\main.c)此函数即为kernel的第一个c函数;
abc中是在汇编代码中处理有关机器ID的相关的东西,启动参数是在start_kernel开始处理;
直到这里,进行各种初始化。
我们移植uboot,kernel等等,最终的目的是什么?是运行我们的应用程序。那么放在哪里?应用程序放在根文件系统中,因此在运行应用程序之前我们要挂在文件系统。
start_kernel最后回去调用rest_init,该函数嗲用kernel_thread,启动一个线程函数kernel_init,在其中调用prepare_namespace,该函数中又调用了mount_root()挂载根文件系统。挂载上根文件系统后,kernel_init中后面调用init_post()执行应用程序。这个启动层级结构如下:
链接脚本:
arch/arm/boot/compressed/vmlinux.lds
#define __setup(str, fn)					\
	__setup_param(str, fn, fn, 0)

#define __setup_param(str, unique_id, fn, early)			\
	 const char __setup_str_##unique_id[] __initconst	 = str; \
	 \
	 struct obs_kernel_param __setup_##unique_id	\
		= { __setup_str_##unique_id, fn, early }
//每一个命令行参数的相关结构体如下:
struct obs_kernel_param {
	const char *str;
	int (*setup_func)(char *);
	int early;
};
/*所有的命令行参数 解析方式放在这个结构体中,所有obs_kernel_param
存放在从__setup_start到__setup_end之间. 
比如early_param("vmalloc", early_vmalloc);
他也放在这个区间, 通过这个宏,他就是early类型的,最终会通过调用do_early_param,
它又会调用early_vmalloc.
总之对于非early的参数还是early类型参数,都会调用它的setup_func函数处理.
经过检验,除了vmalloc以外,所有的参数都是非early类型
*/			
start_kernel //Main.c (init)
	setup_arch(&command_line);
	setup_command_line(command_line);
	parse_early_param(); //参数来自boot_command_line  
		parse_args("early options", cmdline, NULL, 0, do_early_param);
			do_early_param
			  //从__setup_start到__setup_end对于early标识为真就是early的  调用do_early_param 处理
	unknown_bootoption				
		obsolete_checksetup(param)				
			//从__setup_start到__setup_end ,对于early标识为0就是非early的调用obsolete_checksetup进行处理  	       
	rest_init();
		kernel_init
			prepare_namespace();//(init/Do_mounts.c)
					mount_root();//decide what/where to mount, load ramdisks, etc. 
	init_post();//printk(KERN_DEBUG"'%s'\n", line);	


 
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值