内核启动过程分析

Posted 正在起飞的蜗牛

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了内核启动过程分析相关的知识,希望对你有一定的参考价值。

1、uboot引导内核启动

参见博客:《嵌入式开发——uboot如何启动内核(以zImage详解)》

2、找到内核的入口

内核是从汇编代码开始运行,以arm架构的芯片为例,arch/arm/kernel/head.S的ENTRY(stext)处就是起始代码。参考博客:《如何快速确定程序的入口》

3、汇编代码阶段

3.1、设置成SVC模式并禁止终端

setmode	PSR_F_BIT | PSR_I_BIT | SVC_MODE, r9 @ ensure svc mode and irqs disabled

调用setmode去设置CPSR寄存器的中断位和模式位。

3.2、检查内核是否支持当前CPU型号

bl	__lookup_processor_type		@ r5=procinfo r9=cpuid
movs	r10, r5				@ invalid processor (r5=0)?
beq	__error_p			@ yes, error 'p'

参考博客:《内核启动过程中对CPU型号的确认》

3.3、检查内核是否支持当前机器,也就是开发板

bl	__lookup_machine_type		@ r5=machinfo
movs	r8, r5				@ invalid machine (r5=0)?
beq	__error_a			@ yes, error 'a'

参考博客:《内核启动过程中机器码的确定》

3.4、检查uboot传参tag参数

bl	__vet_atags

参考博客:《内核中对uboot传参tags的校验》

3.5、创建临时页表

bl	__create_page_tables

参考博客:《嵌入式开发(S5PV210)——u-boot中开启MMU》

3.6、跳转执行__switch_data函数

ldr	r13, __switch_data

__switch_data:
.long	__mmap_switched
.long	__data_loc			@ r4
······

__switch_data汇编函数在分析启动过程中没什么特别需要关注的,直接跳转到__mmap_switched函数。

3.7、跳转执行__mmap_switched函数

__mmap_switched:
	adr	r3, __switch_data + 4
	······
	b	start_kernel
ENDPROC(__mmap_switched)

__mmap_switched函数就是调用start_kernel函数,跳转到C语言继续进行内核启动。

3.8、执行start_kernel函数

进入C语言阶段继续启动内核,start_kernel函数里是各模块的初始化,下面只对其中常用的模块进行介绍。

4、C语言阶段

4.1、打印内核版本信息:

const char linux_banner[] =
	"Linux version " UTS_RELEASE " (" LINUX_COMPILE_BY "@"
	LINUX_COMPILE_HOST ") (" LINUX_COMPILER ") " UTS_VERSION "\\n";
	
printk(KERN_NOTICE "%s", linux_banner);

linux_banner字符数组保存的是内核的版本等相关信息。在定义linux_banner字符数组时,把那些宏定义包含进去。

4.2、解析uboot传递的tag参数、CPU信息、机器信息

setup_arch(&command_line); 

把uboot传给内核的启动参数保存到command_line变量中;

4.3、解析uboot传递的cmdline

printk(KERN_NOTICE "Kernel command line: %s\\n", boot_command_line);//打印command_line
parse_early_param();
parse_args("Booting kernel", static_command_line, __start___param,
	   __stop___param - __start___param,
	   &unknown_bootoption);

4.4、跳转到rest_init()函数,执行后续的初始化

(1)rest_init()函数调用kernel_thread()函数创建init进程和kthreadd进程;
(2)rest_init()函数最后调用cpu_idle()函数变成0号进程;
(3)内核启动结束;

以上是关于内核启动过程分析的主要内容,如果未能解决你的问题,请参考以下文章

linux内核分析作业3:跟踪分析Linux内核的启动过程

Linux内核的启动过程分析

20135239 益西拉姆 linux内核分析 跟踪分析Linux内核的启动过程

跟踪分析Linux内核的启动过程--实验报告 分析 及知识重点

跟踪分析Linux内核的启动过程

Linux内核及分析 第三周 Linux内核的启动过程