</p> 启动第四步--加载内核) V+ f* e9 ~7 S3 y2 X0 k! t
根据grub设定的内核映像所在路径,系统读取内存映像,并进行解压缩操作。此时,屏幕一般会输出“Uncompressing Linux”的提示。当解压缩内核完成后,屏幕输出“OK, booting the kernel”。
/ [/ K% @9 E* ~3 m# n3 ~ 系统将解压后的内核放置在内存之中,并调用start_kernel()函数来启动一系列的初始化函数并初始化各种设备,完成Linux核心环境的建立。至此,Linux内核已经建立起来了,基于Linux的程序应该可以正常运行了。. t5 E p$ Y( c
start_kenrel()定义在init/main.c中,它就类似于一般可执行程序中的main()函数,系统在此之前所做的仅仅是一些能让内核程序最低限度执行的初始化操作,真正的内核初始化过程是从这里才开始。函数start_kerenl()将会调用一系列的初始化函数,用来完成内核本身的各方面设置,目的是最终建立起基本完整的Linux核心环境。: @7 ^: h" l; B7 j s
start_kernel()中主要执行了以下操作:
6 |1 n. u* l+ Z. o& ^ (1) 在屏幕上打印出当前的内核版本信息。
! P3 l' F y- P+ R' A (2) 执行setup_arch(),对系统结构进行设置。
9 Q2 _9 R# A/ w! Z) x8 l& j. ? (3)执行sched_init(),对系统的调度机制进行初始化。先是对每个可用CPU上的runqueque进行初始化;然后初始化0号进程(其task struct和系统空M堆栈在startup_32()中己经被分配)为系统idle进程,即系统空闲时占据CPU的进程。' j# ~# Z, c6 R1 M. }; X
(4)执行parse_early_param()和parsees_args()解析系统启动参数。
( k4 a4 L, M6 q (5)执行trap_in itQ,先设置了系统中断向量表。0-19号的陷阱门用于CPU异常处理;然后初始化系统调用向量;最后调用cpu_init()完善对CPU的初始化,用于支持进程调度机制,包括设定标志位寄存器、任务寄存器、初始化程序调试相关寄存器等等。" b- V3 G/ H& D& X! Z' D
(6)执行rcu_init(),初始化系统中的Read-Copy Update互斥机制。
* S( |- y' w" y, ] (7)执行init_IRQ()函数,初始化用于外设的中断,完成对IDT的最终初始化过程。, i' s' d6 c8 x& y5 ^$ ~( I
(8)执行init_timers(), softirq_init()和time_init()函数,分别初始系统的定时器机制,软中断机制以及系统日期和时间。
. t+ f: t7 _5 J4 h0 S2 G/ V (9)执行mem_init()函数,初始化物理内存页面的page数据结构描述符,完成对物理内存管理机制的创建。
/ e, J! f, ~/ d6 K (10)执行kmem_cache_init(),完成对通用slab缓冲区管理机制的初始化工作。6 r1 Q* u) E. x. {4 D- Y
(11)执行fork_init(),计算出当前系统的物理内存容量能够允许创建的进程(线程)数量。
" O/ I! J7 f; [$ t- d, J$ w/ | (12)执行proc_caches_init() , bufer_init(), unnamed_dev_init() ,vfs_caches_init(), signals_init()等函数对各种管理机制建立起专用的slab缓冲区队列。
$ l. ]# K7 q1 i0 W (13 )执行proc_root_init()Wl数,对虚拟文件系统/proc进行初始化。
, h" x/ Y: C3 X7 t+ e' N; {( Z- ]+ @ 在 start_kenrel()的结尾,内核通过kenrel_thread()创建出第一个系统内核线程(即1号进程),该线程执行的是内核中的init()函数,负责的是下一阶段的启动任务。最后调用cpues_idle()函数:进入了系统主循环体口默认将一直执行default_idle()函数中的指令,即CPU的halt指令,直到就绪队列中存在其他进程需要被调度时才会转向执行其他函数。此时,系统中唯一存在就绪状态的进程就是由kerne_hread()创建的init进程(内核线程),所以内核并不进入default_idle()函数,而是转向init()函数继续启动过程。
' W( I) X& u+ p- a 启动第五步--用户层init依据inittab文件来设定运行等级) t' J7 M! k- w/ R W
内核被加载后,第一个运行的程序便是/sbin/init,该文件会读取/etc/inittab文件,并依据此文件来进行初始化工作。/ Z; S% K* m( Q$ s9 b& f
其实/etc/inittab文件最主要的作用就是设定Linux的运行等级,其设定形式是“:id:5:initdefault:”,这就表明Linux需要运行在等级5上。Linux的运行等级设定如下:
% s* P8 v6 I9 n) o1 z 0:关机
/ ~2 J) u6 F: y( Q5 d; b 1:单用户模式
+ d J2 |8 I# ~2 @" T 2:无网络支持的多用户模式
, `% ?$ z B7 ?* M6 j$ c 3:有网络支持的多用户模式2 f& q8 s- |/ `2 V3 [+ B1 j; _
4:保留,未使用) j. N7 h- i, V8 S" D! l; \# O3 \
5:有网络支持有X-Window支持的多用户模式1 h& f2 X9 r% S$ }
* o5 N# ^% J( E* f( h% k 6:重新引导系统,即重启 |