</p> start_kernel()中主要执行了以下操作:
( o& Q' ~ ?& ]% w (1) 在屏幕上打印出当前的内核版本信息。
5 \* V1 L" c- q/ N+ \& ~/ I l (2) 执行setup_arch(),对系统结构进行设置。$ h# C& Y/ A! U/ C
(3)执行sched_init(),对系统的调度机制进行初始化。先是对每个可用CPU上的runqueque进行初始化;然后初始化0号进程(其task struct和系统空M堆栈在startup_32()中己经被分配)为系统idle进程,即系统空闲时占据CPU的进程。. V1 q- Y' X$ H2 ^* j ? z
(4)执行parse_early_param()和parsees_args()解析系统启动参数。
* [+ ?7 {% S/ C2 [; ? (5)执行trap_in itQ,先设置了系统中断向量表。0-19号的陷阱门用于CPU异常处理;然后初始化系统调用向量;最后调用cpu_init()完善对CPU的初始化,用于支持进程调度机制,包括设定标志位寄存器、任务寄存器、初始化程序调试相关寄存器等等。
9 A' L9 Z/ H( v, B# S (6)执行rcu_init(),初始化系统中的Read-Copy Update互斥机制。
) t$ j3 t1 D. K& J (7)执行init_IRQ()函数,初始化用于外设的中断,完成对IDT的最终初始化过程。3 R9 a) h) c9 r$ g D3 M+ E
(8)执行init_timers(), softirq_init()和time_init()函数,分别初始系统的定时器机制,软中断机制以及系统日期和时间。
2 |8 f2 O# H' k( L1 ^ (9)执行mem_init()函数,初始化物理内存页面的page数据结构描述符,完成对物理内存管理机制的创建。
" X. N: [2 O3 W9 W, v1 Y" k (10)执行kmem_cache_init(),完成对通用slab缓冲区管理机制的初始化工作。
* @6 W8 p- y+ d* q. I, e, M& f1 W/ v (11)执行fork_init(),计算出当前系统的物理内存容量能够允许创建的进程(线程)数量。& ?3 O$ J1 |/ w7 j$ q" u w
(12)执行proc_caches_init() , bufer_init(), unnamed_dev_init() ,vfs_caches_init(), signals_init()等函数对各种管理机制建立起专用的slab缓冲区队列。9 U0 ]8 b" @2 c3 s# b
(13 )执行proc_root_init()Wl数,对虚拟文件系统/proc进行初始化。
- N. L& w/ q [4 s 在 start_kenrel()的结尾,内核通过kenrel_thread()创建出第一个系统内核线程(即1号进程),该线程执行的是内核中的init()函数,负责的是下一阶段的启动任务。最后调用cpues_idle()函数:进入了系统主循环体口默认将一直执行default_idle()函数中的指令,即CPU的halt指令,直到就绪队列中存在其他进程需要被调度时才会转向执行其他函数。此时,系统中唯一存在就绪状态的进程就是由kerne_hread()创建的init进程(内核线程),所以内核并不进入default_idle()函数,而是转向init()函数继续启动过程。; X& ]" M+ D1 h# ?9 ^6 G3 G
启动第五步--用户层init依据inittab文件来设定运行等级& u" }) w7 S. M) e' _8 K9 u6 i
内核被加载后,第一个运行的程序便是/sbin/init,该文件会读取/etc/inittab文件,并依据此文件来进行初始化工作。- b% Y8 p4 u$ y: f* a, K
其实/etc/inittab文件最主要的作用就是设定Linux的运行等级,其设定形式是“:id:5:initdefault:”,这就表明Linux需要运行在等级5上。Linux的运行等级设定如下:
" M+ K! [( ]1 @# ~- x# | 0:关机% [6 C: _2 u3 |
1:单用户模式2 N7 R& N" q3 l1 }
2:无网络支持的多用户模式" C F3 F1 S1 D) q
3:有网络支持的多用户模式) C8 p7 `5 b* H4 [
4:保留,未使用
3 Q' U, K2 @: \3 F" c& d 5:有网络支持有X-Window支持的多用户模式: m) o3 Z0 f9 A5 W
6:重新引导系统,即重启
/ Z1 H+ G! q( @ 启动第六步--init进程执行rc.sysinit K/ x- Y& S7 |( {& E. B5 m
在设定了运行等级后,Linux系统执行的第一个用户层文件就是/etc/rc.d/rc.sysinit脚本程序,它做的工作非常多,包括设定PATH、设定网络配置(/etc/sysconfig/network)、启动swap分区、设定/proc等等。如果你有兴趣,可以到/etc/rc.d中查看一下rc.sysinit文件。
; j3 c; d$ K- _5 z3 s6 H1 @0 U 线程init的最终完成状态是能够使得一般的用户程序可以正常地被执行,从而真正完成可供应用程序运行的系统环境。它主要进行的操作有:
$ z, {8 p7 b- W8 G' H3 n (1) 执行函数do_basic_setup(),它会对外部设备进行全面地初始化。8 D+ U' N% P7 V4 z% D5 r* w* s& O
(2) 构建系统的虚拟文件系统目录树,挂接系统中作为根目录的设备(其具体的文 件系统已经在上一步骤中注册)。
5 y: `# a3 l3 S3 S2 j0 h9 o' b (3) 打开设备/dev/console,并通过函数sys_dup()打开的连接复制两次,使得文件号0,1 ,2 全部指向控制台。这三个文件连接就是通常所说的“标准输入”stdin,“标准输出”stdout和“标准出错信息”stderr这三个标准I/O通道。8 ?* D0 Y4 {% T( C3 n6 `2 {
: y( s* [8 G; ? (4) 准备好以上一切之后,系统开始进入用户层的初始化阶段。内核通过系统调用execve()加载执T子相应的用户层初始化程序,依次尝试加载程序"/sbin/initl"," /etc/init"," /bin/init',和“/bin/sh。只要其中有一个程序加载获得成功,那么系统就将开始用户层的初始化,而不会再回到init()函数段中。至此,init()函数结束,Linux内核的引导 部分也到此结束。 |