本文主要介绍了Linux系统启动流程相关内容
文章目录
一、概览
开机实际上是一件很复杂的事情,该动作的主要目的就是让冷冰冰的机器帮助我们完成需要的工作。本文所介绍的,只是Linux系统的大致启动过程
需要说明的是,近年来从底层的BIOS到上层的init程序都有了一些变化,而系统启动的大致原理依旧,本章节先以“BIOS”来表示Legacy BIOS与UEFI,以GRUB表示引导程序,以INIT来表示各init程序……,大致说明系统启动过程,后面的章节将分别介绍之
Linux启动大致过程如下
我们知道,计算机只有在CPU加载到指令后才能根据指令完成工作,而其加载的指令存在于RAM(Random Access Memory,随机访问存储器),即我们当前用作内存的介质,而该设备断点后将无法保存数据,那么此时指令从何而来?
在Linux系统初识-计算机体系结构中有介绍过,我们需要外部存储设备来帮助持久保存数据。该设备即外存或辅储,一般使用HDD或SSD为介质
而这就需要在开机时将外存中的指令读取到内存,而后加载到CPU,而这个动作本身,也是需要指令来完成的!这该如何进行?
这就需要计算机有“自举”能力,现代计算机的设计中,在我们按下电源键后,主板将会把一段存储在特殊存储器上的代码传入CPU中,注意,该动作使用硬件逻辑完成的,不需要指令的参与,就像我们打开电灯开关,灯就会亮一样
这段代码我们将其称之为BIOS(Basic Input/Output System,基本输入输出系统),他主要负责探测硬件(POST(Power On Self Test,加电自检))、选择启动设备
当上述操作无误后,BIOS将选择的设备中的代码载入CPU,即Boot Loader,用于引导分区上的操作系统,在此处由于分区表类型不同稍有差异
- 对于完全支持UEFI引导:
- 对于BIOS引导:
由于BIOS本身不能识别文件系统,故要使用其他机制辅助,事实上,上图对于BIOS的引导中,Boot Loader代码也属于Grub程序,而使用UEFI的引导中,Boot Loader即Grub,不同之处下文将详细介绍,为了方便叙述,本文的章节划分按照上图BIOS引导的架构
而后通过Grub实现从当前物理存储设备选择所启动的操作系统,以及内核所在位置与相关启动特性
上述操作完成后,根据Grub中指定的内核与相关参数启动Kernel,在Kernel中启动用户空间的第一个进程,即init程序,至此,系统启动完成
事实上init程序启动后,还会有一些相关配置,此处没有列出,下文将详细介绍
二、BIOS
该过程是计算机加电之后运行的第一段程序,如今,UEFI即将全面取代BIOS,通常,我们将该程序称为固件(Firmware),负责硬件检测,以及为操作系统提供运行时服务
1. BIOS
BIOS(Basic Input/Output System,基本输入输出系统)固件安装在PC的主板(Motherboard)上的独立存储器中,早期位于ROM(Read Only Memory,只读存储器)中,不可更改,后来位于闪存(Flash Memory)中(常为EEPROM),带来的好处是可以在不从主板上移除芯片的情况下重写它,这允许对BIOS固件进行简单的最终用户更新,从而可以添加新功能或修复错误
通常,我们也将存储BIOS的储存器称为BIOS芯片
主要功能
-
BIOS中断服务程序实质上是软件与硬件之间的一个可编程接口,主要用于程序软件功能与硬件之间连接。例如,系统对光驱、硬盘等管理,中断的设置等
-
BIOS系统设置程序:BIOS提供一个“系统设置程序”,主要来设置系统底层的各项参数,如系统的基本情况、CPU特性、软硬盘驱动器等部件的信息,该程序在开机时按某个键就可进入设置状态
-
POST:接通电源后,系统首先由POST(Power On Self Test,加电自检)程序来对内部各个设备进行检查。通常完整的POST自检将包括对CPU、640K基本内存、1M以上的扩展内存、ROM、等进行测试,一旦在自检中发现问题,系统将给出提示信息或鸣笛警告,其测试流程如下1
引导系统重置REST引导CPU。
CPU指向BIOS自我测试的地址FFFFOH并打开CPU运行第一个指令。
CPU内部寄存器的测试。
CMOS 146818 SRAM检查。
ROM BIOS检查码测试。
8254计时/计数器测试。
8237 DMA控制器测试。
74612页寄存器测试。
REFRESH刷新电路测试。
8042键盘控制器测试。
DRAM 64KB基本存储器测试。
CPU保护模式的测试。
8259中断控制器的测试。
CMOS 146818电力及检查码检查。
DRAM IMB以上存储器检查。
显卡测试。
NMI强制中断测试。
8254计时/计数器声音电路测试。
8254计时/计数器计时测试。
CPU保护模式SHUT DOWN测试。
CPU回至实模式(REAL MODE)。
键盘鼠标测试。
8042键盘控制器测试。
8259中断控制器IRQ0至IRQ18建立。
磁盘驱动器及界面测试。
设置并行打印机及串列RS232的界面。
检查CMOS IC时间、日期。
检查完成
- BIOS系统启动自举程序:系统完成POST自检后,BIOS就首先按照系统CMOS设置中保存的启动顺序搜索软硬盘驱动器及CD-ROM,网络服务器等有效地启动驱动器,读入操作系统引导记录,然后将系统控制权交给引导记录,并由引导记录来完成系统的顺序启动
CMOS与BIOS
很多人对二者傻傻分不清,这里说明一下
BIOS是一段程序,存位于EEPROM(Electrically-Erasable Programmable Read-Only Memory,电可擦除可编程只读存储器),是一种可以通过电子方式多次复写的半导体存储设备,可以用特定的电压,来抹除芯片上的信息,以便写入新的数据(注意,早期的BIOS并非如此,上文有介绍)
而BIOS设置的配置记录放在CMOS(Complementary Metal Oxide Semiconductor,互补金属氧化物半导体)芯片中,该芯片属于RAM,断点后数据将丢失
故主板上有一块电池,为该存储器供电,若取出电池,则可重置这些信息,如BIOS密码、启动次序、时间等
Boot Sequence
在BIOS提供的配置页面中,提供了让用户选择启动次序(Boot Sequence)的接口,如下图
上图为VMware Workstation 15的BIOS界面,实际界面样式因不同主板或BIOS程序而异,然意义相同
配置启动设备后,BIOS工作完成后将根据这里配置的顺序从对应设备中寻找启动代码,即查看该设备首512字节是否是以0x55
0xAA
结尾,若不是,则认为该设备无启动能力,继续寻找下一个设备,否则加载该代码,控制权移交至该代码,BIOS工作完成
可参看Linux存储管理相关内容
2. UEFI
UEFI(Unified Extensible Firmware Interface,统一可扩展固件接口)是一种个人计算机系统规格,用来定义操作系统与系统固件之间的软件界面,作为BIOS的替代方案
概述
UEFI的前身是Intel在1998年开始开发的Intel Boot Initiative,后来被重命名为可扩展固件接口(Extensible Firmware Interface,缩写EFI)。Intel在2005年将其交由统一可扩展固件接口论坛(Unified EFI Forum)来推广与发展,为了凸显这一点,EFI也更名为UEFI(Unified EFI)。UEFI论坛的创始者是11家知名计算机公司,包括Intel、IBM等硬件厂商,软件厂商Microsoft,及BIOS厂商AMI(英语:American Megatrends)、Insyde及Phoenix
目前的最新版本为UEFI-2.7A2
UEFI在概念上非常类似于一个小型的操作系统,并且具有操控所有硬件资源的能力,而其一些特性与操作系统有着本质区别
-
它只是硬件和预启动软件间的接口规范
-
UEFI环境下不提供中断的机制,也就是说每个EFI驱动程序必须用轮询(polling)的方式来检查硬件状态,并且需要以解释的方式运行,较操作系统下的机械码驱动效率更低
-
UEFI系统不提供复杂的缓存器保护功能,它只具备简单的缓存器管理机制,具体来说就是指运行在x64或x86处理器的64位模式或保护模式下,以最大寻址能力为限把缓存器分为一个平坦的段(Segment),所有的程序都有权限访问任何一段位置,并不提供真实的保护服务
UEFI的组成
x64计算机平台的UEFI通常包含以下几个部分:3
- Pre-EFI初始化模块
- EFI驱动程序执行环境(DXE)
- EFI驱动程序
- 兼容性支持模块(CSM)
- EFI应用程序
- GUID磁盘分区表
在实现中,统一可扩展固件接口(UEFI)初始化模块和驱动执行环境通常被集成在一个只读存储器中(多为NVRAM)
Pre-EFI初始化程序在系统开机的时候最先得到执行,完成存储器的初始化工作,然后加载UEFI DXE(驱动程序执行环境)
当DXE被加载运行时,系统便具有了枚举并加载其他UEFI驱动程序的能力。在基于PCI Express架构的x64计算机系统中,系统会加载UEFI内置的驱动程序模块,完成UEFI固件、CPU、存储器、芯片组及主板的进一步初始化,然后初始化各PCIe控制器、PCIe适配器(如RAID扩展卡或显卡)及芯片组内置PCIe适配器(如芯片组内置的SATA、USB、网卡等功能)并加载这些PCIe设备的UEFI驱动程序(如果有的话,也有可能是加载PCIe设备的Legacy Option ROM)
UEFI驱动程序不仅可以包含在PCIe适配器的ROM中(作为PCIe设备的UEFI Option ROM),还可以以.EFI文件的形式被方便的加载
在UEFI规范中,一种突破传统MBR磁盘分区结构限制的GUID磁盘分区系统(GPT)被引入,新结构中,磁盘的主分区数不再受限制(在MBR结构下,只能存在4个主分区),另外UEFI+GPT磁盘分割表结合还可以支持2.1 TB以上硬盘,并且分区类型将由GUID来表示
GPT磁盘分区表的硬盘可包含EFI系统分区(ESP),EFI系统分区(ESP)可以被UEFI固件访问,可用于存放操作系统的引导程序、EFI应用程序(如OEM的备份程序和硬件诊断程序)等等
EFI系统分区采用FAT文件系统,在Windows操作系统下默认在“本机”中隐藏。UEFI固件通过运行EFI系统分区中的引导程序文件(扩展名为.EFI的UEFI应用程序)引导操作系统。CSM是在x86平台UEFI系统中的一个特殊的模块,它将为不具备UEFI引导能力的操作系统以及16位的传统Option ROM(即非EFI的Option ROM)提供类似于传统BIOS的系统服务
Secure Boot功能要求原生UEFI(即关闭CSM),因此在UEFI固件设置中打开CSM前,需要在UEFI固件设置中关闭Secure Boot
下图为
引导
UEFI启动
与BIOS不同,UEFI不依赖于引导扇区,而是将引导管理器定义为UEFI规范的一部分。当计算机启动时,启动管理器会检查启动配置并根据其设置加载到内存中,然后执行指定的OS加载程序或操作系统内核。引导配置由存储在NVRAM中的变量定义,包括指示OS加载器和OS内核的文件系统路径的变量
UEFI可以自动检测OS加载程序,从而可以从USB闪存驱动器等可移动设备轻松启动。这种自动检测依赖于到OS加载器的标准化文件路径,路径根据计算机体系结构而变化
从GPT分区磁盘引导UEFI系统通常称为UEFI-GPT引导。尽管UEFI规范要求完全支持MBR分区表[28],但某些UEFI固件实现会立即切换到基于BIOS的CSM引导,具体取决于引导磁盘分区表的类型,从而有效防止UEFI引导从MBR分区磁盘上的EFI系统分区。这样的引导方案通常被称为UEFI-MBR
引导管理器通常具有文本用户界面,因此用户可以从可用引导选项列表中选择所需的OS(或系统实用程序)
CSM启动
为了确保向后兼容性,PC级机器上的大多数UEFI固件实现还支持从MBR分区磁盘通过传统BIOS模式启动,通过提供传统BIOS兼容性的兼容性支持模块(CSM)。在这种情况下,通过忽略分区表并依赖引导扇区的内容,以与基于BIOS的传统系统相同的方式执行引导
从MBR分区磁盘启动BIOS样式通常称为BIOS-MBR,无论是在UEFI还是基于BIOS的传统系统上执行。此外,还可以从GPT磁盘启动传统的基于BIOS的系统,并且这种启动方案通常称为BIOS-GPT
在兼容性支持模块允许传统的操作系统和一些选项ROM仍然使用不支持UEFI。它还提供了所需的传统系统管理模式(SMM)功能,称为CompatibilitySmm,作为UEFI SMM提供的功能的补充。这是可选的,高度芯片组和平台特定。这种传统SMM功能的一个示例是通过模拟其经典的PS / 2对应物,为键盘和鼠标提供USB传统支持
该方案作为目前UEFI与BIOS的过度阶段的缓冲,英特尔宣布计划到2020年逐步停止对CSM的支持
UEFI与BIOS在启动过程上的区别
UEFI启动过程
对应到UEFI个模块为,如下图。事实上,左半部分中,SEC,PEI,DXE称之为PI(Platform Initialization)规范,UEFI纯粹地是一个接口规范,它不会具体涉及平台固件是如何实现的。“如何实现”这一内容是PI要解决的问题
BDS,TSL,和RT一起,属于UEFI规范
- SEC阶段
- SEC阶段内存尚未被初始化,故UEFI将CPU缓存作为内存使用,即Cache As RAM
- PEI阶段
- 和BIOS的初始化阶段类似,PEI阶段用以唤醒CPU及内存初始化。PEI用SEC设置好的Cache As RAM,执行一些PEIM(初始化模块),用于初始化一些硬件
- DXE阶段:
- DXE的主要功能在加载驱动。此阶段所有的内存、CPU、PCI、USB、SATA和Shell等都会被初始化
- BDS阶段:
- 在BDS(引导设备选择)阶段,它负责执行所有符合UEFI驱动模型(UEFI driver model)的驱动。这是一个发现并一个个连接的过程,一个个启动设备被发现,其设备路径(device path)也被连接起来。在万事俱备后,一个界面被显示出来(嵌入式系统上可以没有),供用户进行设置和选择启动设备,这就是大家熟悉的BIOS界面,用户可以自开机管理者程序页,选择要从哪个侦测到的开机设备来启动
- TSL阶段:
- 然后进入TSL(短暂系统载入)阶段,由操作系统接手开机。除此之外,也可以在BDS阶段选择UEFI Shell,让系统进入命令列,进行基本诊断和维护
BIOS启动过程
BIOS启动过程较为简单,一下做大致介绍
-
- 初始化
-
系统加电,CPU会自行重置为初始状态。BIOS boot block初始化阶段启动,此时内存尚未初始化,没有内容可以执行,所以厂商让CPU去寻找系统BIOS ROM中的reset vector(重置向量) :用一个固定的位置来启动所谓的BIOS boot program
-
一般来说程序会在内存的
FFFF0h
处,也就是在UMA(上层记忆区域)靠结尾的地方。为避免ROM大小改变造成兼容问题,所以一般会选择放这里。它的内容只有一个jump指令,进一步跳到真正的BIOS启动程序 -
各家IBV (independent BIOS vender;独立BIOS供应商)可以放在不同的位置,只要通过jump来指定即可
-
在该阶段,系统的CPU、芯片组、Super I/O和USB只有部分初始化,仅获取足够信息来应付万一BIOS开机失败,可以利用其他储存设备来救援BIOS的boot block
-
- POST
-
然后BIOS开始施行POST,它通常被放在内存
C0000h
处,作用是显卡的初始化,而大部分的显示卡都会在显示器上显示其相关讯息。这就是为何各位在开机的时候,首先会在显示器的画面左上角出现有关显示卡讯息的原因。 -
下一步BIOS会显示启动画面,并开始更深入的检测,如果这时候遇到任何错误,就会在画面上显示错误消息
-
- 记录系统的配置
-
此时BIOS会对系统进行进一步的确认,看看你的电脑究竟安装了那些系统资源或设备。有些电脑会逐步显示这些被侦测到的设备,例如BIOS支持随插即用,那它将会侦测和配置随插即用装置,并显示由BIOS侦测到的随插即用设备
-
在这些检测结束后,BIOS会打出一个总结表于画面上。而这个总结表在部分IBV的设定中是可以让使用者开启或关闭的。当然也有些IBV为加速开机把这一步直接隐藏省略
-
- 提供常驻程序
- 提供操作系统或应用程序调用的中断向量,如INT 10h(VGA图形及文字输出中断)等
-
- 加载系统
- 到这里是系统检测的部分,接下来BIOS便开始寻找引导设备,用户可以通过在BIOS的设定来决定搜寻顺序
总结
此处将UEFI与BIOS的引导方式总结如下
- BIOS
-
BIOS只认识设备,不认识分区、不认识文件
-
启动过程:根据CMOS中保存的顺序,查看存储设备,其前512字节是不是以0x55 0xAA结尾?若是则执行这段代码,完成
- UEFI
-
UEFI认识设备,还认识设备ROM,还认识分区表、认识文件系统以及文件
-
启动过程:经过一系列初始化后,按照设置里的顺序寻找启动项,一般有两种类型
- 文件启动项,大约记录的是某个磁盘的某个分区的某个路径下的某个文件。对于文件启动项,固件会直接加载这个EFI文件,并执行
- 设备启动项,大约记录的就是“某个U盘”、“某个硬盘”。(此处只讨论U盘、硬盘)对于设备启动项,UEFI标准规定了默认的路径“\EFI\Boot\bootX64.efi”。UEFI会加载磁盘上的这个文件。文件不存在则失败
-
UEFI-2以后,新增了SecureBoot功能。开了SecureBoot之后,主板会验证即将加载的efi文件的签名,如果开发者不是受信任的开发者,就会拒绝加载
三、Boot Loader
事实上在UEFI+GPT的引导方式下无需该步骤,从上文可看出,若使用该方式引导,由于UEFI可直接识别文件系统,在BDS阶段选择操作系统后即可进入下一步
本章主要介绍没有使用GPT分区表或GPT分区表不被识别的情况,如
- BISO+MBR
- UEFI+MBR
- BIOS+GPT
此处纠正一个问题,很多人认为BIOS+GPT无法引导,其实是可以的,上文已有介绍,GPT分区中LBA0位MBR兼容区。只是由于微软在默认情况下不允许Windows操作系统通过BIOS引导GPT分区而已
然而我们也可以经过配置是的Windows在BIOS+GPT方式下启动,chainloader指定ESP中的bootmgfw.efi即可
故对于BIOS与UEFI、BMR与GPT,其各种组合都是可以引导的,即
- BISO+MBR
- UEFI+MBR
- BIOS+GPT
- UEFI+GPT
若使用UEFI+MBR,则需要使用CSM,即打开兼容性支持模块,如此,UEFI将会读取MBR中的代码,这段过程与BIOS+MBR基本无异
当BIOS(或使用SCM的UEFI)选择到指定的启动设备后,由于它不能识别文件系统,故将读取选择设备的首部446字节,这是一段代码,即Boot Loader(引导加载器),由于代码较为简短,无法执行复杂功能,故其主要用于将执行流执行另一部分
前面已经提及,Boot Loader为Grub的一部分(第一部分),而上面指向的另一部分即Grub的第二部分
可参考Linux存储管理-MBR相关内容
四、GRUB
1. Boot Loader
严格来讲,该章节应该交Boot Loader,而由于上一章MBR中占用,且如今Grub为最著名的Boot Loader程序,此处将其命名为GRUB
这里对Boot Loader程序做简要说明,该程序用于接管BIOS/UEFI交过来的控制系统权,用于加载系统内核
对于Windows,该程序为ntloader,nt即New Technology,而Windows中更新的Boot Loader程序为Windows Boot Manager
对于Linux平台,有两种较为常见
-
LILO,即LInux,LOader,Linux加载器,不能引导1024柱面(Cylinder)以后分区上的内核,故不支持大硬盘,常用于嵌入式平台
-
GRUB,即GRand Unified Bootloader
- Grub 0.x:Grub Legacy
- Grub 2
2. Grub概述
事实上,我们所谓的Grub应该被称为GNU Grub(就像我们每次说的Linux,Stallman先生都会强调:应该是GNU Linux!)
Grub 2引入了一些更为有效的能力:
-
支持多种文件系统,如ext4、xfs、ntfs等
-
Grub 2可以访问已经安装的设备上的数据,可以直接从LAM和RAID中读取数据
-
Grub 2使用了模块机制,引入很多模块,通过动态加载模块来扩展功能,这样允许core镜像足够小。
-
支持自动解压
-
支持脚本语言,包括简单的语法,如条件判断,循环,变量和函数
-
国际化语音,包括支持非ASCII的字符集和类似gettext的消息分类,字体,图形控制台等
-
支持rescue模式,可用于系统无法引导的情况
-
Grub 2有更可靠的方法在磁盘上有多个文件系统时发现文件和目标内核,可以用命令发现系统设备编号或者是UUID
-
有一个灵活的命令接口。如果没有配置文件的存在,grub2会自动进入命令模式
传统Grub在运行时由三个阶段
- Stage 1:位于MBR,用于引导Stage 2
- Stage 1_5:位于MBR之后的扇区,为识别内核文件所在的文件系统提供文件系统识别扩展
- Stage 2:位于/boot分区,主要的引导工作在此完成
其中Stage 1_5非必要
3. Grub的安装位置
这里需要说明的文件为
-
Boot.img:Stage 1对应的文件,MBR分区格式的磁盘中,放在MBR里; GPT分区格式的磁盘中,放在Protective MBR中
-
Core.img:Stage 1_5对应的文件,32256字节大小。MBR分区格式的磁盘中,放在紧邻MBR的若干扇区中;GPT分区格式的磁盘中,则放在34号扇区开始的位置(第一个分区所处的位置),而对应的GPT分区表中的第一个分区的entry被置空
-
/boot/grub:步骤2对应的文件目录,放在系统分区或者单独的Boot分区中
- Grub程序各部分安装的位置如图
-
- MBR分区表:
- MBR分区表:
-
- GPT分区表
- GPT分区表
4. 启动Kernel前的准备
在Grub加载Kernel后,Kernel将启动init程序,以下为./linux.init/main.c
部分代码:
static int __ref kernel_init(void *unused)
{
kernel_init_freeable();
/* need to finish all async __init code before freeing the memory */
async_synchronize_full();
free_initmem();
mark_rodata_ro();
system_state = SYSTEM_RUNNING;
numa_default_policy();
flush_delayed_fput();
if (ramdisk_execute_command) {
if (!run_init_process(ramdisk_execute_command))
return 0;
pr_err("Failed to execute %s\n", ramdisk_execute_command);
}
/*
* We try each of these until one succeeds.
*
* The Bourne shell can be used instead of init if we are
* trying to recover a really broken machine.
*/
if (execute_command) {
if (!run_init_process(execute_command))
return 0;
pr_err("Failed to execute %s. Attempting defaults...\n",
execute_command);
}
if (!run_init_process("/sbin/init") ||
!run_init_process("/etc/init") ||
!run_init_process("/bin/init") ||
!run_init_process("/bin/sh"))
return 0;
panic("No init found. Try passing init= option to kernel. "
"See Linux Documentation/init.txt for guidance.");
}
内核会从三出搜索该程序,若依然没有找到,则启动一个shell,这些程序位于/
(根)下,故而此时Kernel需要有加载根文件系统的能力,而/
的文件系统与/boot
可以位于不同分区,加之Kernel中不可能将所有文件系统的驱动都包含,而此时需要如何访问/
?
我们知道,Boot Loader程序有时需要借助Stage 1_5阶段来加载/boot
所在分区的相应驱动
同样的,将相关文件系统的驱动做成一个特定文件,在Kernel访问/
之前,先加载该文件即可
显然,该文件需要内核能直接访问,故其在/boot
中,在CentOS 5中,该文件为ramdisk
,对应文件名一般为initrd
,而在CentOS 6之后,该文件为ramfs
,对应文件名一般为initramfs
从名称上可以看出,CentOS 5中通过将RAM模拟为块设备,而Linux的缓存机制导致将可能再次在RAM中缓存该内容,造成不必要的浪费,而ramfs本身就是一个tmpfs的内存盘,拥有最小化的设计,绕过了缓存机制,也消除了多余的内存占用
因此,Kernel与initrd(或initramfs)必须存储在Boot Loader程序可以访问的位置,并且需要将initrd(或initramfs)加载后传递其地址给Kernel,如此,内核即可访问根文件系统
5 .Grub Legacy
功能
-
提供菜单,选择要启动时的内核或系统;
- 允许传递参数给内核
- 可以隐藏选择界面
-
提供交互式接口
e
:编辑模式,用于编辑菜单c
:命令模式,交互式接口
-
基于密码的保护
- 启用内核映像,定义在相应的
title
下 - 传递参数,即进入编辑模式,定义在全局段中
- 启用内核映像,定义在相应的
配置文件
配置文件的读取主要在Stage 2完成,其配置文件为/etc/grub.conf
,该文件指向/boot/grub/grub.conf
,如下为RHEL 5中的一个实例,以之为例说明个字段意义
default=0 # 设定默认启动的title的编号,从0开始
timeout=5 # 等待用户选择的内核或OS超时时长,单位:秒
splashimage=(hd0,0)/grub/splash.xpm.gz
# 指定grub的背景图片,gimp工具可以编辑图片,要保存为.xpm格式,然后使用gzip压缩(.gz)
hiddenmenu # 隐藏菜单
password redhat # grub的密码(明文),菜单编辑密码
password --md5 $1$HKXJ51$B9Z8A.X//XA.AtzU1.KuG.
# grub加密密码,可以使用grub-md5-crypt命令来计算密码
title Red Hat Enterprise Linux Server (2.6.18-308.el5)
# 内核标题,或操作系统名称,字符串,可自由修改
root (hd0,0)
# 内核文件所在的设备;对grub而言,所有类型硬盘一律hd,格式为
(hd#,N);
# hd#, #表示第几个磁盘;从0开始编号
# N表示对应磁盘的分区;从0开始编号
kernel /vmlinuz-2.6.18-308.el5 ro root=/dev/vol0/root rhgb quiet
# 内核文件路径,及传递给内核的参数,参数即/proc/cmdline中的内容
# 参数: ro root=/path/to/DEVICE
# 将/path/to/DEVICE所代表的设备当做内核启动时的根,以只读方式挂载
# quiet:静默模式, 内核初始化的信息不再输出
initrd /initrd-2.6.18-308.el5.img
# 文件:通常为cpio归档,并使用gzip压缩,通常以.img作为扩展名
# ramdisk文件路径,即临时的根,是一个完整意义上的Linux
# 注意:以上两项显示根下的文件是由于文件位于/boot/目录,该目录是单独的分区,而此时没有文件系统,遂grub直接访问该分区
# 若/boot没有单独分区,则会正常显示
password --md5 $1$HKXJ51$B9Z8A.X//XA.AtzU1.KuG. # 将该字段放置于所有title上面,为全局密码,放在某一title中,为内核启动密码
title Install Red Hat Enterprise Linux 5
root (hd0,0)
kernel /vmlinuz-5 ks=http://172.16.0.1/workstation.cfg ksdevice=eth0 noipv6
initrd /initrd-5
password --md5 $1$FSUEU/$uhUUc8USBK5QAXc.BfW4m.
命令行
help:获取帮助列表
help KEYWORD:命令详细帮助
find:查找文件
find (hd#,N)/PATH/TO/SOMEFILE
设定根设备后可省略设备
root:设定根设备
root (hd#,N)
kernel:指定本次启动使用的kernel
kernel /PATH/TO/KERNEL_FILE
额外可添加内核支持使用的cmdline参数
init=/PATH/TO/INIT
selinux=0
root=/PATH/TO/ROOT
…
initrd:为选定的内核提供额外文件的ramdisk
initrd /PATH/TO/INITRAMFS_FILE
该文件版本需要与kernel版本完全匹配
boot:引导启动选定的内核
安装grub
可使用grub-install
命令安装grub,使用方式为
grub-install --root-directory=DIR /dev/DISK
还可以在grub交互界面安装:
grub> root (hd#,#)
grub> setup (hd#)
- grub指定设备的方式
-
hd(#,#)
hd#
: 磁盘编号,用数字表示;从0开始编号#
: 分区编号,用数字表示; 从0开始编号
手动在grub命令行接口启动系统
grub> root (hd#,#)
grub> kernel /vmlinuz-VERSION-RELEASE ro root=/dev/DEVICE
grub> initrd /initramfs-VERSION-RELEASE.img
grub> boot
6. Grub 2
Grub 2的软件包名即grub2,他与Grub Legacy的区别上文已有介绍
配置文件
-
/boot/grub2/grub.cfg
:启动项配置,可由grub2-mkconfig
生成 -
/etc/default/grub
:grub2-mkconfig
工具生成配置时的参考信息 -
/etc/grub.d/*
:该目录下主要为一些脚本,分别配合对应grub.cfg
上的各个部分
应用
- 查看当前默认启动项
grub2-editenv list
- 设置默认启动项
- 方式一:
grub2-set-default
- 方式二:修改
/etc/default/grub
,修改GRUB_DEFAULT=#
(#
:该数字为grub菜单中各启动项的顺序),而后使用grub2-mkconfig -o /boot/grub2/grub.cfg
生成配置文件 - 安装grub2
-
grub2-install [--root-directory=/PATH/TO/ROOT] [DEVICE] 若为UEFI,则DEVICE可省略
- 生成新的grub.cfg文件
-
grub2-mkconfig -o /boot/grub2/grub.cfg
五、Kernel
Grub工作完成后,Kernel接管控制权,在此其主要工作为:
- 设备探测
- 驱动初始化(可能会从initrd(在redhat6中叫做initramfs)文件中装载驱动模块)
- 以只读方式挂载根文件系统(稍后init会重新挂载文件系统)
- 装载第一个进程init(PID: 1)
grub中指定的initrd(或initramfs)在此处将会用到,另外,第一个进程在CentOS 7中称为systemd,下一章将介绍
在内核的实现中,我们介绍了当前操作系统内核实现的两种主流方式
- 微内核将通过各内核子系统实现管理工作,如Windows,Solaris
- 宏内核将各种功能集于一身,Linux内核就是这种设计方式
理论上讲,微内核的设计思想更为先进,而事实上要协调好各个子系统去实现复杂管理任务,这本身也是一个非常复杂的工作
Linux内核通过将个功能分为不同的模块,按需动态装卸载,这些模块在Kernel 2.6版本以后本称为Kernel Object,文件名后缀为.ko
(之前为.o
)
BTW,在Linux中共享库为Shared Object(.so
) 共享对象,在Windows中为Dynamic Link Library(.dll
) 动态链接库
Linux内核文件一般位于/boot/vmlinuz-VERSION-RELEASE
,而其模块文件为/lib/modules/VERSION-RELEASE/
,而上文介绍的ramdisk,在CentOS 5中位于/boot/initrd-VERSION-RALEASE.img
,而在CentOS 6之后的版本为/boot/initramfs-VERSION-RELEASE.img
:
[root@localhost ~]# ll /boot/vmlinuz-`uname -r` -h
-rwxr-xr-x. 1 root root 4.8M Mar 6 2015 /boot/vmlinuz-3.10.0-229.el7.x86_64
[root@localhost ~]# ll /lib/modules/`uname -r` -h
total 2.6M
lrwxrwxrwx. 1 root root 38 Dec 20 04:15 build -> /usr/src/kernels/3.10.0-229.el7.x86_64
drwxr-xr-x. 2 root root 6 Mar 6 2015 extra
drwxr-xr-x. 11 root root 4.0K Dec 20 04:15 kernel
-rw-r--r--. 1 root root 668K Dec 20 04:22 modules.alias
-rw-r--r--. 1 root root 644K Dec 20 04:22 modules.alias.bin
-rw-r--r--. 1 root root 1.3K Mar 6 2015 modules.block
-rw-r--r--. 1 root root 5.8K Mar 6 2015 modules.builtin
-rw-r--r--. 1 root root 7.5K Dec 20 04:22 modules.builtin.bin
-rw-r--r--. 1 root root 209K Dec 20 04:22 modules.dep
-rw-r--r--. 1 root root 304K Dec 20 04:22 modules.dep.bin
-rw-r--r--. 1 root root 339 Dec 20 04:22 modules.devname
-rw-r--r--. 1 root root 108 Mar 6 2015 modules.drm
-rw-r--r--. 1 root root 108 Mar 6 2015 modules.modesetting
-rw-r--r--. 1 root root 1.5K Mar 6 2015 modules.networking
-rw-r--r--. 1 root root 82K Mar 6 2015 modules.order
-rw-r--r--. 1 root root 165 Dec 20 04:22 modules.softdep
-rw-r--r--. 1 root root 285K Dec 20 04:22 modules.symbols
-rw-r--r--. 1 root root 356K Dec 20 04:22 modules.symbols.bin
lrwxrwxrwx. 1 root root 5 Dec 20 04:15 source -> build
drwxr-xr-x. 2 root root 6 Mar 6 2015 updates
drwxr-xr-x. 2 root root 91 Dec 20 04:15 vdso
drwxr-xr-x. 2 root root 6 Mar 6 2015 weak-updates
[root@localhost ~]# ll /boot/initramfs-`uname -r`.img -h
-rw-------. 1 root root 20M Jan 18 13:06 /boot/initramfs-3.10.0-229.el7.x86_64.img
在RHEL系列发行版中,/lib/modules/VERSION-RELEASE/
中有对应内核所需的各种外围模块,依赖关系由内核(依赖关系文件modules.dep
)处理
kernel
目录中的内容为内核主要模块:
目录 | 说明 |
---|---|
arch |
平台相关,驱动CPU |
crypto |
加密解密 |
drivers |
驱动 |
fs |
文件系统 |
kernel |
内核自身的额外功能 |
lib |
库 |
mm |
Memory Management,内存管理 |
net |
网络(不是驱动,而是网络协议栈的实现) |
sound |
声卡 |
另外,ramdis由于取药提供文件系统支持,而用户的情况有各不相同,故该文件在安装操作系统时生成,我们亦可自行使用工具生成之:
- CentOS 5:
mkinitrd
- CentOS 6+:
mkinitrd
、dracut
六、init
内核初始化的最后一步就是启动 pid 为 1 的 init 进程。这个进程是系统的第一个进程。它负责产生其他所有用户进程
init 以守护进程方式存在,是所有其他进程的父进程
Init 系统能够定义、管理和控制 init 进程的行为。它负责组织和运行许多独立的或相关的始化工作(因此被称为 init 系统),从而让计算机系统进入某种用户预订的运行模式
仅仅将内核运行起来是毫无实际用途的,必须由 init 系统将系统代入可操作状态。比如启动外壳 shell 后,便有了人机交互,这样就可以让计算机执行一些预订程序完成有实际意义的任务。或者启动 X 图形系统以便提供更佳的人机界面,更加高效的完成任务。这里,字符界面的 shell 或者 X 系统都是一种预设的运行模式
大多数 Linux 发行版的 init 系统是和 System V 相兼容的,被称为 sysvinit。这是人们最熟悉的 init 系统。一些发行版如 Slackware 采用的是 BSD 风格 Init 系统,这种风格使用较少,本文不再涉及。其他的发行版如 Gentoo 是自己定制的。Ubuntu 和 RHEL 采用 upstart 替代了传统的 sysvinit
,启动系统的第一个进程,在RHEL系列的各个发行版中,该程序亦各不相同
-
- CentOS5
- SysV init,进程串行启动
- 配置文件:
/etc/inittab
-
- CentOS6
- Upstart,采用D-Bus、事件驱动模型等新机制4
- 配置文件:
/etc/inittab
,/etc/init/*.conf
-
- CentOS7
-
Systemd
-
配置文件:
/usr/lob/systemd/system
,/etc/systemd/system
-
完全兼容SysV脚本机制,service命令依然可用,建议使用
systemctl
命令来控制服务5
在 Linux 主要应用于服务器和 PC 机的时代,SysVinit 运行非常良好,概念简单清晰。它主要依赖于 Shell 脚本,这就决定了它的最大弱点:启动太慢。在很少重新启动的 Server 上,这个缺点并不重要。而当 Linux 被应用到移动终端设备的时候,启动慢就成了一个大问题。为了更快地启动,人们开始改进 sysvinit,先后出现了 upstart 和 systemd 这两个主要的新一代 init 系统
1. SysV init
2. Upstart init
3. systemd
七、初始化
服务相关内容后续将做介绍 ↩︎