S5PV210Kernel移植5之内核启动C语言阶段

1.这一块的学习思路

1)抓大放小,不深究.

2)感兴趣可以就某个话题去网上搜索资料学习

3)重点局部深入分析

2.具体学习方法

1)顺着代码执行路径抓全。这是我们的学习主线。

2)对照内核启动的打印信息进行分析。

3.几条学习线路

1)分析uboot给kernel传参的影响和实现

2)硬件初始化与驱动加载

3)内核启动后的结局与归宿

4.杂碎

1)smp。smp就是对称多处理器(其实就是我们说的多核心CPU)

2)lockdep。锁定依赖,是一个内核调试模块,处理内核自旋锁死锁问题相关的。

3)cgroup。control group,内核提供的一种来处理进程组的技术。

5.打印内核版本信息

1)代码位于:kernel/init/main.c中的572行

2)printk函数是内核中用来从console打印信息的,类似于应用层编程中的printf。内核编程时不能使用标准库函数,因此不能使用printf,其实printk就是内核自己实现的一个printf。

3)printk函数的用法和printf几乎一样,不同之处在于可以在参数最前面用一个宏来定义消息输出的级别。为什么要有这种级别?主要原因是linux内核太大了,代码量太多,里面的printk打印信息太多了。如果所有的printk都能打印出来而不加任何限制,则最终内核启动后得到海量的输出信息。

4)为了解决打印信息过多,无效信息会淹没有效信息这个问题,linux内核的解决方案是给每一个printk添加一个打印级别。级别定义0-7(注意编程的时候要用相应的宏定义,不要直接用数字)分别代表8种输出的重要性级别,0表示最重要,7表示最不重要。我们在printk的时候自己根据自己的消息的重要性去设置打印级别。

5)linux的控制台监测消息的地方也有一个消息过滤显示机制,控制台实际只会显示级别比我的控制台定义的级别高的消息。譬如说控制台的消息显示级别设置为4,那么只有printk中消息级别为0-3(也可能是0-4)的才可以显示看见,其余的被过滤掉了。

6)linux_banner的内容解析。

6.setup_arch函数简介

1)从名字看,这个函数是CPU架构相关的一些创建过程。

2)实际上这个函数是用来确定我们当前内核的机器(arch、machine)的。我们的linux内核会支持一种CPU的运行,CPU+开发板就确定了一个硬件平台,然后我们当前配置的内核就在这个平台上可以运行。之前说过的机器码就是给这个硬件平台一个固定的编码,以表征这个平台。

3)当前内核支持的机器码以及硬件平台相关的一些定义都在这个函数中处理。

7.Machine查找

1)setup_processor函数用来查找CPU信息,可以结合串口打印的信息来分析。

2)setup_machine函数的传参是机器码编号,machine_arch_type符号在include/generated/mach-types.h的32039-32050行定义了。经过分析后确定这个传参值就是2456.

3)函数的作用是通过传入的机器码编号,找到对应这个机器码的machine_desc描述符,并且返回这个描述符的指针。

4)其实真正干活的函数是lookup_machine_type,找这个函数发现在head-common.S中,真正干活的函数是__lookup_machine_type

5)__lookup_machine_type函数的工作原理:内核在建立的时候就把各种CPU架构的信息组织成一个一个的machine_desc结构体实例,然后都给一个段属性.arch.info.init,链接的时候会保证这些描述符会被连接在一起。__lookup_machine_type就去那个那些描述符所在处依次挨个遍历各个描述符,比对看机器码哪个相同。

8.setup_arch函数进行了基本的cmdline处理

1)这里说的cmdline就是指的uboot给kernel传参时传递的命令行启动参数,也就是uboot的bootargs。

2)有几个相关的变量需要注意:

default_command_line:看名字是默认的命令行参数,实际是一个全局变量字符数组,这个字符数组可以用来存东西。

CONFIG_CMDLINE:在.config文件中定义的(可以在make menuconfig中去更改设置),这个表示内核的一个默认的命令行参数。

3)内核对cmdline的处理思路是:内核中自己维护了一个默认的cmdline(就是.config中配置的这一个),然后uboot还可以通过tag给kernel再传递一个cmdline。如果uboot给内核传cmdline成功则内核会优先使用uboot传递的这一个;如果uboot没有给内核传cmdline或者传参失败,则内核会使用自己默认的这个cmdline。以上说的这个处理思路就是在setup_arch函数中实现的。

9.实验验证内核的cmdline确定

1)验证思路:首先给内核配置时配置一个基本的cmdline,然后在uboot启动内核时给uboot设置一个bootargs,然后启动内核看打印出来的cmdline和uboot传参时是否一样。

2)在uboot中去掉bootargs,然后再次启动内核看打印出来的cmdline是否和内核中设置的默认的cmdline一样。

注意:uboot给内核传递的cmdline非常重要,会影响内核的运行,所以要谨慎。有时候内核启动有问题,可以分析下是不是uboot的bootargs设置不对。

注意:这个传参在这里确定出来之后,还没完。后面还会对这个传参进行解析。解析之后cmdline中的每一个设置项都会对内核启动有影响。

思考:内核为什么要这样设计?

10.setup_command_line

也是在处理和命令行参数cmdline有关的任务。

11.parse_early_param&parse_args

1)解析cmdline传参和其他传参

2)这里的解析意思是把cmdline的细节设置信息给解析出来。譬如cmdline:console=ttySAC2,115200 root=/dev/mmcblk0p2 rw init=/linuxrc rootfstype=ext3,则解析出的内容就是就是一个字符串数组,数组中依次存放了一个设置项目信息。

console=ttySAC2,115200    一个

root=/dev/mmcblk0p2 rw  一个

init=/linuxrc                    一个

rootfstype=ext3                      一个

3)这里只是进行了解析,并没有去处理。也就是说只是把长字符串解析成了短字符串,最多和内核里控制这个相应功能的变量挂钩了,但是并没有去执行。执行的代码在各自模块初始化的代码部分。

12.杂碎

1)trap_init                                  设置异常向量表

2)mm_init                                  内存管理模块初始化

3)sched_init                              内核调度系统初始化

4)early_irq_init&init_IRQ            中断初始化

5)console_init                                    控制台初始化

总结:start_kernel函数中调用了很多的xx_init函数,全都是内核工作需要的模块的初始化函数。这些初始化之后内核就具有了一个基本的可以工作的条件了。

如果把内核比喻成一个复杂机器,那么start_kernel函数就是把这个机器的众多零部件组装在一起形成这个机器,让他具有可以工作的基本条件。

1)这个函数之前内核的基本组装已经完成。

2)剩下的一些工作就比较重要了,放在了一个单独的函数中,叫rest_init。

总结:start_kernel函数做的主要工作:打印了一些信息、内核工作需要的模块的初始化被依次调用(譬如内存管理、调度系统、异常处理•••)、我们需要重点了解的就是setup_arch中做的2件事情:机器码架构的查找并且执行架构相关的硬件的初始化、uboot给内核的传参cmdline。

13.rest_init和操作系统去哪里了?

1)rest_init中调用kernel_thread函数启动了2个内核线程,分别是:kernel_init和kthreadd

2)调用schedule函数开启了内核的调度系统,从此linux系统开始转起来了。

3)rest_init最终调用cpu_idle函数结束了整个内核的启动。也就是说linux内核最终结束了一个函数cpu_idle。这个函数里面肯定是死循环。

4)简单来说,linux内核最终的状态是:有事干的时候去执行有意义的工作(执行各个进程任务),实在没活干的时候就去死循环(实际上死循环也可以看成是一个任务)。

5)之前已经启动了内核调度系统,调度系统会负责考评系统中所有的进程,这些进程里面只有有哪个需要被运行,调度系统就会终止cpu_idle死循环进程(空闲进程)转而去执行有意义的干活的进程。这样操作系统就转起来了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值