Linux内核启动

说到内核启动,很多这方面的资料都是从bootloader(BIOS)开始说起的,严格说来,那时候还没有出现Kernel的概念呢,实际的Kernel是在start_kernel()函数之后才真正启动的。在这之前,主要干的活:

1. 解压缩,把未压缩的内核包放在RAM的指定地址,然后从这个地址开始执行。

2.体系结构相关的初始化,初始化的目的也是为启动内核做准备,包括页表初始化啊,MMU,Cache,TLB等的初始化啊,最终在完成这些准备工作后跳转到start_kernel开始真正的内核之旅。

 

注意,在跳转到start_kernel前,中断时未经初始化且未使能的,这个工作就在start_kernel中完成。同时比较关键的还包括进程管理器(进程调度子程序)的初始化。接下来还有更多的内核模块的初始化,例如,定时器,内存管理,虚拟文件系统,信号量等等等等。反正在第一个内核进程启动前所应作的准备工作都必须全部完成。

在函数start_kernel的最后,会调用函数rest_init(),这个函数就是要启动进程啦。

在函数rest_init()中,第一个干的活就是创建内核线程(函数kernel_thread()),这样内核线程所需的所有结构就准备完毕了,接下来就是调用著名的schedule()函数,开始启用这个内核线程了。这个内核线程就是1号任务了。此后,理论上就有2个任务正在运行了,一个目前的完成各类初始化的主程序(亦称0号任务),另一个则是刚启用的1号任务。但事实上,0号任务不属于调度的范围(永远不可能被调度到),它在创建并启用1号任务后就cpu_idle()了(实际就是CPU空闲了(此处没有用睡眠是因为睡眠时进程才有的,但我的理解CPU空闲和睡眠没啥本质区别))。

OK,0号死了,1号出现了,那么1号究竟在哪儿呢?1号任务就位于源码的/init/main.c文件中,入口为__init init()函数。

init()函数完成更高层次的一些初始化工作,如驱动程序初始化,根文件系统初始化。在这之后,调用函数init_post(),这个post非常重要,它会去尝试依次加载6个程序。

1)内核启动参数"rdinit=xxx"指定的程序(实际就是加载ramdisk文件系统)

2)内核启动阐述"init=xxx"指定的程序()

3)/sbin/init

4)/etc/init

5)/bin/init

6)/bin/sh

只要这几个中的一个或者若干个加载成功,就可以进入用户态,从而整个内核启动宣告结束了。

1号任务在加载外部程序后就有了自己的用户态空间,从而成为第一个进程,这就是所谓的祖先进程了。这个祖先进程在用户态会继续做一些工作,如创建终端,等待用户输入等,系统启动就全面完成了。

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值