linux系统启动过程

Linux 启动过程如下图所示,依次经过BIOS加电自检,加载主引导加载程序,加载次引导加载程序,加载linux内核映像,运行init进程,完成启动过程。

BIOS自检

BIOS(Basic Input / Output System),又称基本输入输出系统,可以视为是一个永久地记录在ROM中的一个软件,是操作系统输入输出管理系统的一部分。早期的BIOS芯片确实是"只读"的,里面的内容是用一种烧录器写入的,一旦写入就不能更改,除非更换芯片。现在的主机板都使用一种叫Flash EPROM的芯片来存储系统BIOS,里面的内容可通过使用主板厂商提供的擦写程序擦除后重新写入,这样就给用户升级BIOS提供了极大的方便。

当你打开计算机电源,计算机会首先加载BIOS信息,BIOS信息是如此的重要,以至于计算机必须在最开始就找到它。这是因为BIOS中包含了CPU的相关信息、设备启动顺序信息、硬盘信息、内存信息、时钟信息、PnP(Plug and Play,即插即用)特性等等。在此之后,计算机心里就有谱了,知道应该去读取哪个硬件设备了。BIOS的功能由两部分组成,分别是POST码(Power-on self test)和Runtime服务。POST阶段完成后它将从存储器中被清除,而Runtime服务会被一直保留,用于目标操作系统的启动。BIOS两个阶段所做的详细工作如下:

步骤1:上电自检POST,主要负责检测系统外围关键设备(如:CPU、内存、显卡、I/O、键盘鼠标等)是否正常。例如,最常见的是内存松动的情况,BIOS自检阶段会报错,系统就无法启动起来

   步骤2:步骤1成功后,便会执行一段小程序用来枚举本地设备并对其初始化。这一步主要是根据我们在BIOS中设置的系统启动顺序来搜索处于活动状态并且可以引导的设备,如硬盘、光盘、U盘、软盘和网络等,用户可以在BIOS界面中boot选项设置启动顺序。以从硬盘启动为例,BIOS此时去读取硬盘驱动器的第一个扇区(硬盘上第0磁道第一个扇区被称为MBR,也就是Master Boot Record,即主引导记录,它的大小是512字节,里面却存放了预启动信息、分区表信息),将里面的主引导加载程序加载到RAM中。实际上这里BIOS并不关心启动设备第一个扇区中是什么内容,它只是负责读取该扇区内容、并执行。至此,BIOS的任务就完成了,此后将系统启动的控制权移交到MBR。在个人电脑中,Linux的启动是从0xFFFF0地址开始的。

加载引导加载程序

首先加载主引导加载程序MBR,系统找到BIOS所指定的硬盘的MBR后,就会将其复制到0×7c00地址所在的物理内存中。其实被复制到物理内存的内容就是Boot Loader(Boot Loader 就是在操作系统内核运行之前运行的一段小程序,主要作用就是加载linux内核,因此也称为内核加载程序),而具体到你的电脑,那就是lilo或者grub了。主引导加载程序通过分区表查找活动分区,将活动分区的次引导加载程序从设备读入RAM中并运行。

当开机时BIOS读入MBR的前446B的程序代码(第一阶段代码),该段代码运行后,将载入第二阶段代码,并进入GRUB的开机选项单,将内核映像和根文件系统映像从flash上读到ram空间中,为内核设置启动参数等。

加载及启动内核

以Grub(grand

unified bootloader)为例来讲解,系统读取内存中的grub配置信息(一般为menu.lst或grub.lst),并依照此配置信息来启动不同的操作系统。

实际上,从MBR载入boot loader开始到init程序之间所有的操作都是GRUB(grand unified bootloader)这个多重开机管理程序锁负责的。

一旦次引导加载程序被加载到内核中,便会显示GRUB的启动菜单图形界面(列出了这台计算机上可以启动的所有操作系统),可以通过方向键选择需要加载的操作系统及它们的内核,如下图所示

在该界面上,按e键进入GRUB的启动菜单项编辑界面。使用方向键选择菜单项中的行,使用e键编辑当前选中的行,b键启动当前的菜单项(GRUB选中当前的操作系统内核开机)。

在GRUB的启动菜单项编辑界面可以对GRUB配置文件已经存在的启动项做进一步调整,如对现有命令行编辑,最后按b键以当前的配置启动。在该编辑界面所做的修改只对本次启动有效,并不保存在配置文件中,如若需要改变配置,可编辑配置文件/boot/grub/grub.conf。


若不进行任何选择操作,GRUB将在5s后自动启动/boot/grub/grub.conf文件中设置的默认操作系统,GRUB确定要启动的操作系统后,会定位相应的内核映像所在的/boot/目录,内核映像文件形如/boot/vmlinuz-version.*

[root@toor boot]# ls

config-2.6.18-194.el5PAE  initrd-2.6.18-194.el5PAE.img  symvers-2.6.18-194.el5PAE.gz  vmlinuz-2.6.18-194.el5PAE

grub                      lost+found                    System.map-2.6.18-194.el5PAE

GRUB的配置可以通过grub.conf文件来完成

[root@toor ~]# vi/boot/grub/grub.conf

# grub.conf generated by anaconda

#

# Note that you do not have torerun grub after making changes to this file

# NOTICE:  You have a /boot partition.  This means that

#          all kernel and initrd paths arerelative to /boot/, eg.

#          root (hd0,0)

#          kernel /vmlinuz-version roroot=/dev/VolGroup00/LogVol00  #内核存在在/dev/VolGroup00/LogVol00分区

#          initrd /initrd-version.img

#boot=/dev/sda                                                #启动盘是/dev/sda

default=0           #设置GRUB默认启动的操作系统,GRUB计数从0开始,0表示第一个

timeout=5          #默认等待时间,5s内没有选择,启动默认操作系统

splashimage=(hd0,0)/grub/splash.xpm.gz      #设定开机时使用的背景图案,

hiddenmenu

#title 选项设置操作系统显示在GRUB选择菜单中的名称,如有其它操作系统,接下来显示title other选项

title Red Hat Enterprise LinuxServer (2.6.18-194.el5PAE)

        root (hd0,0)             #设置grub程序将要使用的文件所在的目录

#设置内核文件的名称,命名规则是vmlinuz-<版本号>,若单独为boot划分分区则内核文件前的路径是”/“,若没有单独分区,内核文件前面的路径是”/boot/“

#要载入的内核,后面试传递的内核参数,ro:readonly意思

kernel /vmlinuz-2.6.18-194.el5PAEro root=/dev/VolGroup00/LogVol00 rhgb quiet

#initrd指定用来初始化的linux

image,并设置参数

        initrd /initrd-2.6.18-194.el5PAE.img#initrd映像文件装入内存,该映像文件存放的是一些启动程序

其中,(hd0,0)是grub的路径表示法,hd0表示第一个硬盘,逗号后面的0表示这个硬盘上的第一个分区,这个系统中,/boot分区对应着/dev/sda,所以第一个硬盘的第一个分区就是/boot分区。splashimage的设定是指开机时使用的背景图案,其指定的开机背景图案文件存放在/boot/grub目录中的splash.xpm.gz文件中。

[NSOS 1.1 ~]# cd /boot/grub/

[NSOS 1.1 grub]# ll spl*

-rw-r--r-- 1 root root 55808 Mar17  2009 splash.xpm.gz

[NSOS 1.1 grub]#

ro root=/dev/VolGroup00/LogVol00,以LVM的指定方式挂载根(/)目录。quiet,表示不显示开机时候的出错信息。


GRUB将内核映像加载到内存中,并进行解压操作,然后加载到内存中执行。至此,引导加载程序GRUB完成任务,将控制权交给内核映像,由内核完成接下来的系统引导工作。

Grub根据/boot/grub.conf配置文件中的设置的信息,从/boot/所在的分区中系统读取内存映像,并进行解压缩操作。此时,屏幕一般会输出“Uncompressing

Linux”的提示。当解压缩内核完成后,屏幕输出“OK,

booting the kernel”。

系统将解压后的内核放置在内存之中,并调用start_kernel()函数来启动一系列的初始化函数并初始化各种设备,发现设备后,将这些设备的驱动程序初始化并载入内核中,装载根文件系统,并以只读方式挂在根目录下,完成Linux核心环境的建立。至此,Linux内核已经建立起来了,基于Linux的程序应该可以正常运行了。此后系统的控制权就全权交给/sbin/init进程了。

运行init进程

内核被加载后,第一个运行的程序便是/sbin/init,init进程是LINUX系统所有进程的起点,它对应的执行文件为/sbin/init,它是系统中所有进程的发起者和控制者,所有的进程都有它衍生。所以,init进程的进程号是1,init进程启动后,会初始化操作系统,并启动特定的运行级别下的自动运行程序。

[root@test24266 ~]# ps -ef | grepinit

root         1    0 0  2017 ?        00:00:02 /sbin/init

init进程扮演者充当父进程的角色,那些失去了父进程的子进程都会以init作为它们的父进程,另外一作用是读取/etc/inittab文件,在进入某个特定的运行级别时运行相应的程序,以此对各种运行级别进行管理。

[NSOS 1.1 ~]# pstree

init─┬─brcm_iscsiuio───3*[{brcm_iscsiuio}]

├─bypassapp

├─crond

├─dbus-daemon

├─direct_cpu.sh───direct_cpu.sh───direct_cpu.sh─┬─awk

│├─2*[grep]

│└─mpstat

系统初始化

/sbin/init进程是系统其他所有进程的父进程,当它接管了系统的控制权先之后,会读取/etc/inittab配置文件,首先执行/etc/rc.d/rc.sysinit脚本,根据这个脚本完成如配置环境变量、配置网络、启用swap、挂载文件系统等、设定/proc等等。rc.sysinit所做的事情(不同的Linux发行版,该文件可能有些差异)如下:

(1)获取网络环境与主机类型。首先会读取网络环境设置文件"/etc/sysconfig/network",获取主机名称与默认网关等网络环境。

(2)测试与载入内存设备/proc及usb设备/sys。除了/proc外,系统会主动检测是否有usb设备,并主动加载usb驱动,尝试载入usb文件系统。

(3)决定是否启动SELinux。

(4)接口设备的检测与即插即用(pnp)参数的测试。

(5)用户自定义模块的加载。用户可以再"/etc/sysconfig/modules/*.modules"加入自定义的模块,此时会加载到系统中。

(6)加载核心的相关设置。按"/etc/sysctl.conf"这个文件的设置值配置功能。

(7)设置系统时间(clock)。

(8)设置终端的控制台的字形。

(9)设置raid及LVM等硬盘功能。

(10)以方式查看检验磁盘文件系统。

(11)进行磁盘配额quota的转换。

(12)重新以读取模式载入系统磁盘。

(13)启动quota功能。

(14)启动系统随机数设备(产生随机数功能)。

(15)清楚启动过程中的临时文件。

(16)将启动信息加载到"/var/log/dmesg"文件中。

 [root@toor ~]# more /etc/rc.d/rc.sysinit

#!/bin/bash

#

#/etc/rc.d/rc.sysinit - run once at boot time

#

#Taken in part from Miquel van Smoorenburg's bcheckrc.

#

 

HOSTNAME=`/bin/hostname`               #设置主机名

HOSTTYPE=`uname-m`                  #设置系统类型

unamer=`uname-r`

 

set -m

 

if [-f /etc/sysconfig/network ]; then            #初始化网络

    . /etc/sysconfig/network

fi

if [-z "$HOSTNAME" -o "$HOSTNAME" = "(none)" ]; then             #如果主机名未设置,用localhost作为主机名

    HOSTNAME=localhost

fi

 

if [ !-e /proc/mounts ]; then                                #挂载文件系统

        mount -n -t proc /proc /proc

        mount -n -t sysfs /sys /sys >/dev/null2>&1

fi

if [ !-d /proc/bus/usb ]; then

        modprobe usbcore >/dev/null2>&1 && mount -n -t usbfs /proc/bus/usb /proc/bus/usb

else

        mount -n -t usbfs /proc/bus/usb/proc/bus/usb

fi

 

./etc/init.d/functions

 

#Check SELinux status

接下来,init进程执行/etc/inittab文件中的代码,其实/etc/inittab文件最主要的作用就是设定Linux的运行等级,init进程会查找并执行系统设置的运行级别所对应的服务脚本文件(如果设定run

level为5,那么就会将5这个参数传给/etc/rc.d目录中的rc程序,它的含义就是执行/etc/rc.d/rc5.d目录中的所有程序)。

接下来执行/etc/rc.d/rc.local,打开了此文件,里面有一句话,读过之后你就会对此命令的作用一目了然:

# This scriptwill be executed *after* all the other init scripts.

# You can putyour own initialization stuff in here if you don’t

# want to do thefull Sys V style init stuff.

 rc.local就是在一切初始化工作后,Linux留给用户进行个性化的地方。如果所做的修改只在引导开机的时候起作用,你可以把你想设置和启动的东西放到这里,这个脚本程序将在引导过程的最后一步执行。

最后一步,执行/bin/login,完成了系统所有的启动任务后,linux会启动终端或X-Window来等待用户登录。所谓的登录呢,就是输入用户名和密码,如果输入正确,则会给你一个Bash(或者别的Shell)让你操作计算机,如果输入不正确,则让你继续输入…。getty给了让你登录并且继续输入的机会。init进程不断调用getty,然后getty会发起login让你登录,当你输入正确的用户名和密码后,ttyXYZ就是你的了,如果你是用SSH进行的login,那么你将得到一个叫做/dev/pts/X,如果你是通过显示器用键盘登录,你将得到/dev/tttX(X取决于当前的焦点终端)。tty1,tty2,tty3...这表示在运行等级1,2,3,4的时候,都会执行"/sbin/mingetty",而且执行了6个,所以linux会有6个纯文本终端,mingetty就是启动终端的命令。除了这6个之外还会执行"/etc/X11/prefdm-nodaemon"这个主要启动X-Window至此,系统就启动完毕了。

你可能感兴趣的:(linux系统启动过程)