内核的启动流程

版权声明:本文为博主原创文章,任何组织或者个人可以在任何媒介上发表或转载我的文章、图片等.且转载后必须注明出处和邮箱,博客地址(https://blog.csdn.net/u011011827),本人邮箱([email protected]) https://blog.csdn.net/u011011827/article/details/83030119
前言
本文基于linux-4.0
内核的启动流程非常复杂.大概分为三个过程

内核启动流程0_解压内核文件


//这个流程不是必须的
//如果内核镜像没有压缩(vmlinux),就不需要解压缩
//但如果压缩了,可以让bootloader解压,然后也可以让内核解压,一般是内核自解压

1.发生条件
	内核为压缩文件,且bootloader 没有解压内核
2.上序
      uboot将控制权交付内核
3.代码位置
    arch/arm/boot/compressed/head.S 中 的 start 标号
4.非易失性存储器位置
    如果是uImage,在flash中镜像所在首地址+0x40
    如果是桌面发行版,bootloader 支持文件系统,/boot/vmlinuz
5.易失性存储器位置
    如果是uImage,则在 Entry Point
6.入口符号
    start标号
7.出口符号
    arch/arm/kernel/head.S 中的 stext
8.功能
    decompress_kernel
    将控制权交给 arch/arm/kernel/head.S 中的 ENTRY(stext)
9.问题
    什么时候打印什么东西到终端?
        Uncompressing Linux... done, booting the kernel // 此次打印不依赖 控制台的注册
    这时候内核已经启动了,怎么会再次解压呢?
        启动的部分没有解压,启动的部分是解压代码. arch/arm/kernel/head.S 及其他文件被压缩了
    解压之后将stext放到哪里?
        TODO
    移植需要什么 Load Address Entry Point 一定要和 tftp地址 bootm 地址 对应.

内核启动流程1_开发板相关


1.发生条件
  这个过程是必须的
2.上序
	内核解压或者uboot控制权转移
3.代码位置
    arch/arm/kernel/head.S
4.非易失性存储器位置
    如果是桌面发行版,bootloader 支持文件系统,/boot/vmlinuz
5.易失性存储器位置
    TODO
6.入口符号
    arch/arm/kernel/head.S 中的 ENTRY(stext)
7.出口符号
  	start_kernel
8.功能
		检查cpu id / board id / bootargs 的 合法性
		设置页表,使能mmu
    	复制数据段,清bss端
    	调用 start_kernel 函数

9.移植需要注意什么
    1. 第一条代码运行了吗?怎么验证? // 点灯法,注意点灯使用的寄存器不要和源代码冲突
    2. cpu id 
    3. board id
    

内核启动流程2_开发板无关


1.发生条件
  必须
2.上序
  开发板相关代码
3.代码位置
  	init/main.c
4.入口符号
  	start_kernel
7.出口符号
  	run_init_process // 运行用户程序 "/sbin/init"
5.执行流程
  	...
  	setup_arch//板子相关
  		parse_early_param//处理 early param
	...
  	setup_command_line
  	...
  	parse_early_param
  	parse_args//处理console tag // 此时printk 打印的东西 在 test buf 中
  	...
  	console_init // 此时会调用 register_console 来注册 console ,可能会在这里打印出来之前 printk 打印的东西.
  				 // 最终会调用 console_unlock 来打印
  				 // 如果此时没有打印出来,则一般会在 do_initcalls  打印出来 
  				 // console_initcall 注册的函数会在 do_initcall_level (level=3) 的时候被调用,一般用来 register_console
  	...
  	rest_init
  	    kernel_init //init内核线程建立
  	        kernel_init_freeable
  	            do_basic_setup // 建立设备
  	                driver_init // 初始化驱动架构
  	                do_initcalls // 做 0-7 level 的初始化,这些初始化主要是设备相关的初始化. 网络协议栈 在 level 5 初始化
  	            prepare_namespace // 挂载根文件系统(flash 上的 jffs2文件系统)或者网络文件系统
  	        free_initmem // 最后一次打印内核log 就是在这里
  	        run_init_process // 运行 运行用户程序 "/sbin/init"
6.功能
    做初始化,将控制权交给用户程序
    注意:此时内核只是将一部分控制权交由用户程序,不过内核掌握着绝对的控制权.
    内核交付控制权后,会开始服务用户,但又同时防止用户对内核造成破坏.
7.下序
    用户进程

8.问题
    1.内核是什么?
        1.在启动之初,内核是初始化程序
        2.在启动之后,内核是 内核代码 及 内核线程的集合
    2.为什么一开始是内核态?
        arm芯片规定,reset 异常会将 cspr 改写为 SVC模式, 此模式 特权级 为 高特权级. //高特权级就意味着内核态.
    3.什么时候走向用户态?
        run_init_process 调用 do_execve 
    4.移植需要注意什么
        u-boot bootargs 中的 "root=" "init="
        prepare_namespace 中的挂载文件系统使用到的驱动(网络驱动,块驱动)


参考资料

https://wenku.baidu.com/view/ed87e7e8fe4733687f21aa3a.html

http://www.cnblogs.com/yr-linux/p/5495734.html

http://blog.sina.com.cn/s/blog_54f82cc2010127s9.html

http://blog.csdn.net/dianhuiren/article/details/6863965

http://www.embedu.org/Column/Column13.htm

猜你喜欢

转载自blog.csdn.net/u011011827/article/details/83030119