理解Linux的启动过程

从按下PC电源,到出现熟悉的bash提示符"$"或进入漂亮的KDE/GNOME桌面,这是我们每天开机必经的过程。那么,在这短短几十秒内,Linux是怎样启动的呢?本文介绍Linux的启动过程。

  平台:PC机, Ubuntu 5.10

  基础知识

  BIOS (Basic I/O System,基本输入/输出系统)

  BIOS,完整地说应该是ROM-BIOS,是只读存储器基本输入/输出系统的简写,它实际上是被固化到计算机中的一组程序,为计算机提供最低级的、最直接的硬件控制。准确地说,BIOS是硬件与软件程序之间的一个“转换器”或者说是接口(虽然它本身也只是一个程序),负责解决硬件的即时需求,并按软件对硬件的操作要求具体执行。

  从功能上看,BIOS分为三个部分:

  1.自检及初始化程序;

  2.硬件中断处理;

  3.程序服务请求。

  这里我们主要关注第一部分——自检及初始化程序:这部分负责启动计算机,具体有三个部分,第一个部分是用于计算机刚接通电源时对硬件部分的检测,也叫做加电自检(POST),功能是检查计算机是否良好,例如内存有无故障等。第二个部分是初始化,包括创建中断向量、设置寄存器、对一些外部设备进行初始化和检测等,其中很重要的一部分是BIOS设置,主要是对硬件设置的一些参数,当计算机启动时会读取这些参数,并和实际硬件设置进行比较,如果不符合,会影响系统的启动。

  最后一个部分是引导程序,功能是引导DOS或其他操作系统。BIOS先从软盘或硬盘的开始扇区读取引导记录,如果没有找到,则会在显示器上显示没有引导设备,如果找到引导记录会把计算机的控制权转给引导记录,由引导记录把操作系统装入计算机,在计算机启动成功后,BIOS的这部分任务就完成了。

  关于BIOS的详细介绍,可以google一下,这篇文章就不错。

  硬盘

  就物理组成来说,一个硬盘封装里有多个盘片(platter),每个盘面有两个面(surface)。在盘片上都有一个磁头(head)来进行硬盘盘片的读/写,盘片绕轴(spinder)旋转一周时磁头所走过的轨迹即磁道(track),所有盘片的同一磁道构成了磁柱(cylinder)。磁道又被分为多个扇区(sector),扇区是最小的磁盘存储单位,即硬盘分区时的最小单位——通常为512KB。磁道由缝隙(gap)分开,gap中存储的不是数据位,而是用来确认扇区的格式位。

  MBR

  主引导扇区(MBR, Master Boot Recorder)是硬盘中最重要的部分,它记录了硬盘的分区信息、引导信息。CU上面有一篇介绍MBR的文章。

  注意这里所说的MBR是指BIOS中指定的启动设备中的MBR。如果以软盘启动,则MBR是软盘的第一个扇区。如果是硬盘,则是硬盘的第一个扇区。如果有多个硬盘呢?那么就是BIOS中指定启动硬盘的第一个扇区!

  run-level

  运行  $ less /etc/inittab

  显示下列信息:

  # /etc/init.d executes the S and K scripts upon change

  # of runlevel.

  #

  # Runlevel 0 is halt.

  # Runlevel 1 is single-user.

  # Runlevels 2-5 are multi-user.

  # Runlevel 6 is reboot.

  上面显示的就是当前可用的登录模式,共有0~6中级别。常用的是3和5。

  0:关机

  1:单用户模式(系统有问题时的登录模式,相当于WINDOWS的"安全模式“)

  2:对于Debian/Ubuntuare来说,2~5都是相同的——多用户图形界面模式。对于其他发行版来说,3可能是多用户文本模式,4为系统保留,5为多用户图形模式,具体的定义可以查看该发行版对应的/etc/inittab文件内容。

  6:重新启动

  另外,还可能有"S"级,它等同于1的单用户级别。

  运行 $ runlevel 可以查看系统当前运行级别

  如果把运行级别设成了0或6,想象会出现什么情况?如何解决呢?

  WINDOWS在启动时,如果按下F8,会出现“安全模式“、”正常启动“、”MS-DOS“模式的选择。相当于Linux run-level的1,5,3(不对应于Debian/Ubuntu)。

  关于Debian/Ubuntu中的run-level,看这里!

  基本流程

  1, 加载BIOS硬件信息,并取得第一个开机装置的代号。

  2,加载第一个开机装置中MBR的boot loader(即lilo, grub, spfdisk等)引导信息。

  3,加载Linux内核,内核开始解压缩,并驱动硬件。

  4,内核执行init程序,并获得run-level信息;

  5,init 执行 /etc/init.d/rcS 程序;

  6,加载内核模块(module)

  7,init 执行 对应run-level 级的脚本文件( Scripts );

  8,执行 /bin/login 程序,等待用户登入;

  9,用户登入之后,开始以shell控制系统(如果以图形界面登录,则运行图形界面)。

  下面具体介绍流程中的步骤:

  1,加载BIOS

  系统上电时,最先读取BIOS信息。BIOS(Basic Input/Output System)是计算机与外设最底层的接口,它存储了计算机启动时最先加载的数据,包括:CPU类型、启动设备顺序、硬盘大小/类型、芯片组工作状态、外设I/O地址、PnP (Plug and Play,既插既用设备)的开启与否、内存时钟等。

  读取了BIOS设定值后,系统根据BIOS数据进行开机自我检测(Power On Self Test, POST),对硬件进行初始化,并设定PnP设备,指定启动设备,之后从磁盘的MBR中读取Bootloader数据。

  2,加载Boot Loader

  系统读完BIOS之后,接着加载第一个引导磁盘的第一个扇区(MBR),boot loader就位于MBR中。此时,启动工作的接力棒就交到了boot loader的手中。

  常用的boot loader有lilo, grub, spfdisk等,现在最流行的是grub,我用的Ubuntu中,boot loader就是grub,本文假设boot loader是grub,其实基本原理都是一样的。

  为什么要在MBR中安装boot loader呢?它到底有什么作用?实际上,boot loader的作用就是加载OS内核。系统在启动时,要读取文件以加载内核,必须能够识别硬盘文件系统,但这时候系统还在启动过程中,对文件系统信息一无所知。boot loader就辅佐系统识别文件格式,加载内核。boot loader不仅不光能够识别Linux内核,而且能识别WINDOWS内核.所以,如果要安装多系统,那么要在MBR中安装能支持这些系统文件系统的 boot loader.

  如果是以grub启动,加载它后,会有个选择启动那个OS的菜单,当你作出选择后,grub就从被选定OS所在的扇区中加载相应的内核.

 

 

 

  3,加载内核

  在grub的菜单选定启动Linux后,系统从Linux所在的磁盘载入内核。内核一般位于/boot目录中,比如,我的系统中内核为 /boot/vmlinuz-2.6.12-10-686。当然,可以有不同版本的内核位于/boot目录中,可以通过grub菜单选择启动的内核版本。

  $ uname -r  : 显示当前运行的内核版本

  vmlinuz是可引导的、压缩的内核。“vm”代表“Virtual Memory”。vmlinux是未压缩的内核,vmlinuz是vmlinux的压缩文件.

  加载内核时还应该注意”虚拟硬盘“,即RAM DISK。以后有机会再归纳。


图1 有建立RAM Disk可能的启动流程


图2 更明了的启动流程

  总之,boot loader现将Linux内核加载到内存中(可能基于initrd建立RAM DISK),然后将BIOS中关于设备的数据传递给内核,内核建设设备,加载相应的驱动程序.

  4,init进程

  内核被加载之后,它执行的第一个程序就是/sbin/init.init 它利用 /etc/inittab配置文件获取开机等级 ( Run level ) 之外, 并基于run level 选择开机时启动的服务.

  通过 $ less /etc/inittab 查看开机init读取的开机配置文件内容.注意下面这行:

  # The default runlevel.

  id:2:initdefault:

  Ubuntu默认的run level是2.正如前面所说,把它设置成2,3,4,5都是多用户图形模式登录.千万别设成0或6!

  关于init进程,这里多说几句(针对一般UNIX系统)

  pid=0 : swapper进程,用于进程调度.它位于内核内部,是系统进程.

  pid=1 : init进程, 有对应的程序/sbin/init,尽管运行它需要管理员权限,但实际上它是个用户进程,不位于内核中.系统启动时,内核被加载后调用init进程.

  pid=2 : pagedaemon, 用于支持虚拟内存的页.

  init进程还负责处理孤儿进程(父进程在子进程之前终止,则子进程成为孤儿进程, 此时,init继承为他们的父进程).

  5,init 执行 /etc/init.d/rcS 程序 (重点)

  在Debian/Ubuntu系统中,初始化脚本是/etc/init.d/rcS,在Rad Hat中是/etc/rc.d/rc.sysinit。这里面包含了装入文件系统,设置时间,打开交换分区,得到主机名等等内容。

  在前面提到的inittab文件中,紧接runlevel之后有如下内容:

  # Boot-time system configuration/initialization script.

  # This is run first except when booting in emergency (-b) mode.

  si::sysinit:/etc/init.d/rcS

  inittab的主要功能是描述引导及正常操作时,应该在何种运行等级下启动什么程序,每个运行等级的具体项目完全可以通常/etc/inittab来定义,但Debian有一个更健壮的方案sysvinit,它被认为是init最强大的应用程序之一。Debian组织inittab的方式是把运行等级的大部分定义从inittab中移出来,移到一个脚本层次中去。惟一直接从inittab启动的程序只有getty,它用于虚拟设备上启动登录提示符,保留它因为它们要求特殊处理,在inittab之外处理要困难得多。

  inittab来启动所有软件当然是可能的,但将所有配置写在同一个文件既不方便查看也不方便维护,所以文件里会加上这许多行:

  l0:0:wait:/etc/init.d/rc 0

  l1:1:wait:/etc/init.d/rc 1

  l2:2:wait:/etc/init.d/rc 2

  l3:3:wait:/etc/init.d/rc 3

  l4:4:wait:/etc/init.d/rc 4

  l5:5:wait:/etc/init.d/rc 5

  l6:6:wait:/etc/init.d/rc 6

  这些行实际决定了系统在各个运行等级下的行为。它们如何做到的也许并不明显,但至少我们知道主要意思:首先每行都有个符号ID lx,lx表示runlevel x;其次,每行只在一个运行等级下激活,该运行等级对应着符号ID中的数字x。命令执行时,init停下来,直到进程结束。最后,每个命令行调用一个脚本 /etc/init.d/rc x,这里x代表当前运行等级的数字。显然各运行等级的具体任务在/etc/init.d/rcS脚本中安排。

  init把从inittab中获取的run-level值作为参数传递给rc

  rc与rcS脚本的区别 (rc = run command)

  rc   : This file is responsible for starting/stopping services when the runlevel changes.

  rcS : Call all S??* scripts in /etc/rcS.d in numerical/alphabetical order.

  6,加载内核模块(module)

  2.6的内核支持动态模块的加载,关于内核模块,我另外写一篇。

  7,init 执行 对应run-level 级的脚本文件( Scripts )

  到目前为止,内核及其模块被加载了,也完成了系统的初始化。现在要做的工作就是开启系统服务。由于不同的run-level需要开启的服务不同,所以系统为不同的run-level设定了不同的脚本。

  $ ls -d /etc/rc*.d

  可以看到有rc0~rc6及rcS,共8个目录。他们所包含的文件都是连接,指向/etc/init.d/目录中的文件。比较各目录中的文件你会发现, rc2~rc5中的内容是相同的。正好验证了Debian/Ubuntu中run-level 2~5是等效的。

  以S开头的表示在对应级别Start的服务,以K开头表示Kill的服务。紧跟S或K之后的两位数字决定了启动顺序,数字小的先运行。

  关于rcS/rcS.d,我还不是很清楚,哪位大侠指点?

  8,执行 /bin/login 程序,等待用户登入

  这个就不用多说了。看过APUE的都知道login要读取/etc/passwd文件。关于passwd文件,请参考APUE,p161 (第二版新版哦!)

  OK,完毕,谢谢收看。有不足之处,恳请指正!

  在系统加电引导时,init从run-level = 0开始,一级一级往上运行到inittab中定义的默认run-level。在run-level过渡时,init将run-level值作为参数传递给rc,进而执行启动脚本。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值