本文基于linux-4.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.发生条件
这个过程是必须的
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
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