固件(firmware)是指设备最底层的,让设备得以运行的程序代码。简单理解就是:固定在硬件上的软件。计算机中的许多设备都拥有固件(如硬盘、鼠标、光驱、U盘等),在计算机启动过程中,最先读取的就是位于主板上的固件,这个固件当前有两种类型:传统的BIOS和新的通用性更强的UEFI。

在上一篇中,我们提到另一种磁盘分区格式GTP也是UEFI标准的一部分。于是,当前计算机启动中,出现了两种不同的方式:BIOS/MBR和UEFI/GTP。
在linux操作系统的世界中,同样在经历着变革,系统初始化软件sysvinit正逐渐被systemd取代。
本文将主要讲述传统的BIOS/MBR-->sysvinit启动方式,同时,作为补充,也将简述UEFI/GTP-->systemd的启动方式。
BIOS/MBR-->sysvinit 1、BIOS阶段系统加电后会立即读取BIOS中内容并执行,BIOS中程序的执行包括两个步骤:
1)加电自检POST(power-on self test),主要负责检测系统外围设备(如CPU、内存、显卡、键盘鼠标等)是否正常。如果硬件出现问题,主板会发出不同含义的蜂鸣声,启动终止。如果没有问题,屏幕就会显示出CPU、内存、硬盘等信息。
2)自检完成后,BIOS会执行一段程序来枚举本地设备(如光盘、U盘、硬盘、网络等,可以在BIOS中设置枚举顺序)寻找下一阶段的启动程序所在位置。BIOS会将控制权交给启动顺序(Boot Sequence)中排在第一位的设备,此时,计算机读取该设备中的最前面的512个字节,如果这512个字节的最后两个字节是0x55和0xAA(Magic Number),表明这个设备可以用于启动;如果不是,表明该设备不能用于启动,控制权于是转交给启动顺序中的下一个设备。如上一篇所述,硬盘中的最前面的512字节即为主引导记录 MBR。
2、MBR阶段前一篇中我们描述过MBR的结构,其中包括446字节的Bootloader,64字节的DPT和2字节的Magic Number。
Bootloader(引导加载程序)中较常用的一种是grub,grub引导分为两个阶段(有些grub还定义了1.5阶段):
1)BIOS将stage1载入内存中的指定位置(0x7C00)并跳转执行,stage1的内容即为MBR中起始的446字节;此阶段执行作用主要是将硬盘0磁头0磁道2扇区的内容载入到内存0x8000处并跳转执行。
1.5)由于stage2的代码(较大)存放在文件系统下的/boot分区中(或者/boot没有单独分区的/etc/),因此识别stage2文件需要文件系统环境(此时还只能直接读取硬盘指定位置的内容,并不能识别文件系统)。stage1.5的作用就是为stage2提供文件系统环境,使系统能够找到位于文件系统中的stage2文件。
2)stage2被载入内存并执行,它首先会解析grub的配置文件menu.lst即/boot/grub/grub.conf,该文件中指定了系统内核文件所处的位置,如果没有找到该文件,就会执行一个shell,等待用户手动指定内核文件的位置。此阶段的最终状态就是执行boot命令,将内核和initrd镜像载入内存,进而将控制权交给内核。
grub.conf内容(版本:GNU GRUB 0.97):
#grub.confgeneratedbyanaconda # #Notethatyoudonothavetorerungrubaftermakingchangestothisfile #NOTICE:Youhavea/bootpartition.Thismeansthat #allkernelandinitrdpathsarerelativeto/boot/,eg. #root(hd0,0) #kernel/vmlinuz-versionroroot=/dev/sda3 #initrd/initrd-version.img #boot=/dev/sda default=0 timeout=5 splashimage=(hd0,0)/grub/splash.xpm.gz hiddenmenu titleCentOS(2.6.18-407.el5) root(hd0,0) kernel/vmlinuz-2.6.18-407.el5roroot=LABEL=/rhgbquiet initrd/initrd-2.6.18-407.el5.img titleCentOS(2.6.18-398.el5) root(hd0,0) kernel/vmlinuz-2.6.18-398.el5roroot=LABEL=/rhgbquiet initrd/initrd-2.6.18-398.el5.img文件中#开头的行是注释行,最重要的部分是两个title下面指定的内核位置及具体文件(kernel和initrd项)
3、内核阶段grub的stage2将initrd文件加载到内存中,内核于是开始执行initrd中的init文件,此文件是一个脚本,主要作用是加载各种存储介质相关的设备驱动程序。当所需的驱动程序加载完成后,会创建一个根设备,然后将根文件系统(rootfs)以只读的方式挂载。这一步结束后,释放未使用的内存,转换到真正的根文件系统中运行程序/sbin/init,启动系统PID为1的进程。此后系统的控制权就交给/sbin/init进程了。
4、init阶段当init进程接管了系统的控制权之后,它首先会读取/etc/inittab文件,此文件描述了在特定的运行级别(runlevel)下,init进程该如何初始化系统。
linux中定义了7种运行级别: 0表示关机 1表示单用户模式 2表示无网络的多用户模式 3表示多用户模式 4未使用 5表示图形界面模式 6表示重启inittab文件中指定了系统的默认运行级别,如id:3:initdefault:表示默认运行级别为3(多用户模式)。
init进程根据inittab文件,运行一系列指定的初始化脚本:
1)/etc/rc.d/rc.sysinit系统初始化脚本,它的作用包括设置主机名和默认网关、决定是否启用SELinux、加载用户自定义模块、根据文件/etc/sysctl.conf设置内核参数、设置raid及LVM等硬盘功能、重新以读写方式挂载根文件系统等等
2)执行/etc/rc.d/rc文件,该文件确认由inittab指定的运行级别N,并启动相应级别下的服务(通过执行/etc/rc.d/rcN.d中的文件),例如运行级别为3时,则先执行/etc/rc.d/rc3.d下以K开头的文件,然后执行以S开头的文件。这些文件都是指向/etc/init.d下的符号链接。以K开头的文件表示此运行级别下需要关闭的服务,以S开头的文件表示此运行级别下需要开启的服务。
3)在运行级别2、3、4、5中最后一个执行的文件均指向文件/etc/rc.local,用户可以在此文件中自定义启动内容。
4)之后根据inittab中设置,运行6个终端,以便用户登录系统,如果是运行级别5,则还会执行/etc/X11/prefdm -nodaemon启动相应的桌面环境。
5)然后执行/bin/login程序用于接收和验证来自mingetty的用户名和密码。
至此整个系统即启动完毕了
UEFI/GTP-->systemdUEFI的出现是为了代替BIOS,同样,GTP和systemd也是为了弥补MBR和sysvinit的不足。和BIOS只负责POST和找到MBR不同,UEFI将贯穿系统加电到关机的整个过程。粗略划分,UEFI系统启动分为4个阶段:
1、UEFI初始化阶段1)SEC(安全验证):接收并处理系统启动和重启信号,初始化临时存储区域,传递系统参数给下一阶段(即PEI)。
2)PEI(EFI前期初始化):为DXE准备执行环境,将需要传递到DXE的信息组成HOB(Handoff Block)列表,最终将控制权转交到DXE手中。
3)DXE(驱动执行环境):根据HOB列表初始化系统服务,然后遍历固件中的所有Driver,当驱动的依赖资源满足时,调度Dirver到执行队列执行,直到所有满足条件的Dirver都被加载。
2、操作系统加载器作为UEFI应用程序运行阶段1)BDS(启动设备选择):初始化控制台设备,加载必要的设备驱动,根据系统设置加载和执行启动项,用户选中某个启动项(或系统进入默认的启动项)后,OS Loader启动,系统进入TSL阶段。
UEFI中程序能够识别存储介质上的分区信息和文件系统(如:fat32),此时会将/EFI/boot/grub2.efi(位于GTP格式硬盘的一个分区ESP,安装时自动生成)作为UEFI应用程序运行。
2)TSL(临时系统加载):操作系统加载器(OS Loader也位于ESP分区)执行的第一阶段,在这一阶段OS Loader作为一个UEFI应用程序运行,系统资源仍然由UEFI内核控制。当启动服务的ExitBootServices()服务被调用后,系统进入RT(Run Time)阶段。
3、操作系统运行阶段RT(运行时):系统的控制权从UEFI内核转交到OS Loader手中,UEFI占用的各种资源被回收到OS Loader,仅有UEFI运行时服务保留给OS Loader和OS使用。随着OS Loader的执行,OS最终取得对系统的控制权。
在init作为系统初始化程序时,服务是通过/etc/rc.d/init.d中的脚本来管理并且是顺序执行的,当使用systemd作为系统初始化程序后,这些脚本被服务单元替换,并尽可能的并行启动进程。
在systemd中,一个单元配置文件可以描述如下内容之一:
系统服务(.service) 挂载点(.mount) 套接字(.sockets) 系统设备(.device) 交换分区(.swap) 文件路径(.path) 启动目标(.target) 由systemd管理的计时器(.timer) ....systemd为保持向下兼容性还保留了一些init命令和概念,但所对应的文件都是指向systemd对应命令或文件的符号链接:
[root@centos7temp]#ls-l/sbin/init lrwxrwxrwx.1rootroot221月152016/sbin/init->../lib/systemd/systemd [root@centos7temp]#ls-l/usr/lib/systemd/system/runlevel*.target lrwxrwxrwx.1rootroot151月152016/usr/lib/systemd/system/runlevel0.target->poweroff.target lrwxrwxrwx.1rootroot131月152016/usr/lib/systemd/system/runlevel1.target->rescue.target lrwxrwxrwx.1rootroot171月152016/usr/lib/systemd/system/runlevel2.target->multi-user.target lrwxrwxrwx.1rootroot171月152016/usr/lib/systemd/system/runlevel3.target->multi-user.target lrwxrwxrwx.1rootroot171月152016/usr/lib/systemd/system/runlevel4.target->multi-user.target lrwxrwxrwx.1rootroot161月152016/usr/lib/systemd/system/runlevel5.target->graphical.target lrwxrwxrwx.1rootroot131月152016/usr/lib/systemd/system/runlevel6.target->reboot.targetsystemd启动后执行的第一个目标是default.target,但实际上default.target是指向graphical.target的符号链接。
[root@centos7temp]#ls-l/usr/lib/systemd/system/default.target lrwxrwxrwx.1rootroot161月152016/usr/lib/systemd/system/default.target->graphical.target [root@centos7temp]#cat/usr/lib/systemd/system/graphical.target #Thisfileispartofsystemd. # #systemdisfreesoftware;youcanredistributeitand/ormodifyit #underthetermsoftheGNULesserGeneralPublicLicenseaspublishedby #theFreeSoftwareFoundation;eitherversion2.1oftheLicense,or #(atyouroption)anylaterversion. [Unit] Description=GraphicalInterface Documentation=man:systemd.special(7) Requires=multi-user.target Wants=display-manager.service Conflicts=rescue.servicerescue.target After=multi-user.targetrescue.servicerescue.targetdisplay-manager.service AllowIsolate=yes其中Requires行指明了本单元的依赖关系(其他各项意义可以通过命令man systemd.unit查看),顺着此文件,可以找到需要执行的单元:multi-user.target、basic.target、sysinit.target、local-fs.target swap.target、local-fs-pre.target。
4、关机阶段AL(After-life):当系统硬件或操作系统出现严重错误不能继续正常运行时,固件会尝试修复错误,这时系统进入AL期。UEFI标准并没有定义此阶段的行为和规范。系统供应商可以自行定义。
相关命令 init1、init
init除了在系统初始化时起的重要作用外,还可以用来执行关机、重启、切换运行级别的作用:
#关机 init0 #重启 init6 #切换到单用户模式 init12、runlevel 显示运行级别
[root@centos7temp]#runlevel N3 [root@centos7temp]#输出中N表示当前运行级别,如果系统启动后切换过运行级别,则输出类似于3 5表示之前运行级别为3,现在的运行级别为5。
3、halt reboot poweroff shutdown
#立即关机 shutdown-hnow #在11:50分执行关机 shutdown-h11:50 #如果要取消指定时间的关机,则在另一个终端中执行: shutdown-c #过30分钟之后重启系统,并且重启时不进行磁盘检测 shutdown-fr+304、chkconfig 更新或查询服务的运行级别信息
#列出服务(还会列出xinetd管理的服务) chkconfig--list #增加一个服务 chkconfig--addhttpd #使服务在运行级别2、3、5时自启动 chkconfig--level235httpdon5、service 运行服务脚本(服务脚本位于/etc/init.d内,service本身也是脚本,位于/sbin内)
#列出所有服务状态 service--status-all #列出单个服务状态 servicenginxstatus