linux操作系统启动流程

1、BIOS
#前言就像人的肉体和思想的关系一样,计算机硬件是软件的躯体,软件是硬件的灵魂。没有硬件,软件无从谈起;没有软件,硬件就是一堆垃圾,毫无用处。众所周知,操作系统是系统软件,对硬件的操控和各种应用软件的运行都要依靠操作系统。操作系统控制硬件资源并提供核心功能(软件运行的平台),它可以识别硬盘上的文件系统并进一步读取和运行上面的软件,因此我们才能达成各种任务。可以说,操作系统赋予了硬件生命,让硬件“活”了起来;操作系统为软件提供了生命必需品,让软件得以存活。让硬件有生命、让软件活下去之后,操作系统还充当桥梁让它们得以沟通。但是,按下开机按钮时操作系统并没有启动,此刻是谁在负责和硬件沟通呢?而操作系统本身也是一种软件,那又是谁来识别这个系统软件并且运行它的?或者换个问法?进入OS之后,OS是硬件和软件的桥梁,那进入OS之前,谁是硬件和OS的桥梁呢?这就要靠计算机的开机程序。目前的电脑,在开机程序上,主要有早期的BIOS和现在的UEFI两种。#BIOS(Basic Input Output System)BIOS,基本输入输出系统,就是写入到主板上的一个程序。也是开机时计算机主动执行的第一个程序。CMOS(Complementary Metal Oxide Semiconductor),互补金属氧化物半导体。它是指制造大规模集成电路芯片用的一种技术或用这种技术制造出来的芯片,是电脑主板上的一块可读写的RAM芯片。因为可读写的特性,所以在电脑主板上用来保存BIOS设置的各项硬件参数,这个芯片仅仅是用来存放数据的。BIOS启动后,首先会分析计算机里有哪些存储设备。以硬盘为例,BIOS会根据设置(CMOS)取得能够开机的硬盘,然后到该硬盘里面去读取第一个扇区的MBR位置。这个扇区中存放的446B的MBR信息保存着最基本的开机管理程序。到此,BIOS工作完成,接下来就交给MBR内的开机管理程序。这个开机管理程序的目的是载入操作系统内核。开机管理程序是操作系统在安装时提供的,所以它可以识别硬盘的文件系统,因此就能够读取文件,然后工作完成,接下来就交给内核,实际上就是操作系统,去运行。大致流程就是:1、BIOS:开机主动执行的固件,能识别第一个可开机的设备2、MBR:第一个可开机设备的第一个扇区内的MBR信息块,内含开机管理程序3、开机管理程序(boot loader):一个可读取操作系统核心文件来执行的软件4、OS内核:操作系统的功能总结起来,BIOS干两件事——找硬盘,找MBR;boot loader干两件事——识别文件系统,载入内核。从上面也可以看出来,BIOS和MBR是硬件本身会支持的功能,而boot loader是操作系统安装在MBR上的一个软件。整个MBR核心内容只有446B,所以boot loader也非常小,它主要有以下功能:1、提供菜单:选择不同的开机项目2、载入OS内核:直接指向可开机的程序区段来开始操作系统3、转交其他loader:将开机管理功能转交其他loader负责计算机可以存放不止一个boot loader,安装多个操作系统时就会有多个boot loader。一块硬盘只能有一个MBR,但是boot loader不仅可以保存到MBR中,还可以保存到任何其他分区的开机扇区(boot sector)。正是因为这个功能,多系统多重开机才得以实现。比如,第一个分区安装Windows,第二个分区安装Linux,此时的开机菜单中,M1直接进入Windows,M2则进入到Linux系统的boot loader。loader只认自己系统的核心文件和其他的loader。有个说法是,如果要安装双系统,要先安装Windows,再安装Linux。因为Windows在安装时它的loader会直接覆盖掉MBR以及自己所在分区的开机扇区,没有选择的机会。而安装Linux则可以选择安装到MBR或者是安装到其他分区的开机扇区。
2、UEFI

#EFI介绍在介绍UEFI之前,我们需要先了解一下EFI是什么。EFI是由Intel提出的,目的在于为下一代的BIOS开发树立全新的框架。EFI的前身是Intel在1998年开始开发的Intel Boot Initiative,后来被重命名为 Extensible Firmware Interface,即EFI,可扩展固件接口。EFI是英文Extensible Firmware Interfaces的缩写。正如它的名字一样,EFI不是一个具体的软件,而是在操作系统与平台固件(platform firmware)之间的一套完整的接口规范。BIOS 没有制定相应规范。BIOS 本身就是一项事实标准,从 20 世纪 80 年代开始,BIOS 的工作方式就一成不变。EFI最早是在Spring 2000 IDF(Intel Developer’s Forum)上提出的,当时Intel认为,随着IBM在80年代初推出了第一台个人计算机开始,直到今天为止,个人计算机硬件平台已经发生了翻天覆地的变化,相关的系统软件如操作系统等也从最早的MS DOS1.0到后来的的Windows XP,而作为整个系统的最底层也最为关键的系统软件之一的BIOS却基本上保持了架构二十年不变。这在整个软件史上都是一件不可思议的事情。如今,BIOS已经变成了严重阻碍IT产业前进的绊脚石,必须通过对BIOS的革新来为下一代的操作系统提供更加强大的支持。大致意思非常明确,EFI就是用来替换传统BIOS.作为更好的BIOS,EFI可以提供过去无法在BIOS中作到的许多事情。#为什么要替换BIOS在早期的计算机系统中,英特尔的8086处理器工作在1M实模式下,也就是说,它最多只能访问1MB的内存。这个限制主要是由于8086处理器的地址总线宽度只有20位,最多只能寻址到2的20次方,也就是1MB的内存。(模块1的8.14 IBM PC使用的是intel的8088处理器,8088处理器基于intel的8086处理器)然而,随着技术的发展,计算机的内存容量已经远远超过了1MB。新的处理器也能够访问更大的内存空间。但是,由于传统的BIOS仍然基于8086的1M实模式,这就意味着新的处理器在启动过程中,必须首先进入1M实模式,然后再切换到保护模式或者长模式,才能访问更大的内存空间。这个过程不仅复杂,而且也会浪费处理器的性能。因为处理器在启动过程中,必须在不同的模式之间切换,这就像是一辆跑车在高速公路上却只能以慢速行驶,显然是对性能的一种浪费。此外,由于BIOS是固定的,缺乏文档,完全基于经验和晦涩约定的一个事实标准,这就导致了其扩展性非常不好。例如,BIOS不能直接支持新的硬件设备,每当需要支持新的硬件设备时,都必须更新BIOS。而且,由于缺乏标准,不同的BIOS可能会有不同的实现方式,这就使得硬件制造商需要为不同的BIOS提供不同的驱动程序,增加了开发的复杂性。因此,英特尔提出了EFI(可扩展固件接口),并逐渐发展为UEFI。可以这么理解,如果说BIOS是一部老旧的黑白电视,那么UEFI就像是一台智能彩电。它不仅具备了播放电视节目的基本功能,还能够接入网络,播放网络视频,甚至还能安装各种应用,功能强大,扩展性极强。#UEFI的产生Intel在2005年将EFI其交由统一可扩展固件接口论坛(Unified EFI Forum)来推广与发展,为了凸显这一点,EFI也更名为UEFI(Unified EFI)。UEFI论坛的创始者是11家知名电脑公司,包括Intel、IBM等硬件厂商,软件厂商Microsoft,及BIOS厂商AMI、Insyde及Phoenix。有关EFI的规范,2002年12月英特尔释出其订定的版本—1.1版,然后英特尔已于2005将此规范格式交由UEFI论坛来推广与发展,UEFI论坛于2005年发放2.0版本的规格。1.002002 年首个正式版本,基于英特尔 EFI 1.10 规范,引入模块化设计、图形界面和 64 位支持。2.02005 年增加安全启动(Secure Boot)的基础架构,改进驱动模型和协议规范。2.12006 年完善安全启动功能,支持更多加密算法,增强固件更新机制。2.22007 年改进网络堆栈,增加对 IPv6 的支持,优化驱动程序加载流程。2.32009 年引入 UEFI Shell 2.0,增强脚本支持和诊断工具,改进设备管理。2.3.12011 年强化安全启动验证流程,增加对固件签名的严格检查,修复安全漏洞。2.42012 年支持 PCI Express 3.0 和 SATA 3.0,优化电源管理,改进硬件资源分配。2.52013 年增加对 NVMe(非易失性内存 express)存储设备的原生支持,改进 UEFI 驱动模型。2.62015 年引入固件运行时服务(Firmware Runtime Services)的改进,增强虚拟化支持。2.72016 年支持 ACPI 6.1,增加对新硬件标准(如 USB 3.1、Thunderbolt)的支持,改进电源管理。2.82018 年完善安全启动规范,支持 UEFI 固件卷(FV)压缩,增强固件更新的可靠性。2.92020 年支持 ACPI 6.3,改进 NVMe 和 SCSI 存储协议,增加对 TPM 2.0 的扩展支持。2.102022 年引入固件信任根(Root of Trust),增强供应链安全,支持新的加密算法(如 SHA - 3)。2.112023 年改进固件更新机制,增加对动态配置的支持,优化低功耗设备的 UEFI 实现。#UEFI介绍UEFI(Unified Extensible Firmware Interface),统一可扩展固件接口,是一种个人电脑系统规格,用来定义操作系统与系统固件之间的软件界面,作为BIOS的替代方案。UEFI负责加电自检(POST)、联系操作系统以及提供连接操作系统与硬件的接口。作为传统BIOS(Basic Input/Output System)的继任者,UEFI拥有前辈所不具备的诸多功能,比如图形化界面、多种多样的操作方式、允许植入硬件驱动等等。这些特性让UEFI相比于传统BIOS更加易用、更加多功能、更加方便。而Windows 8在发布之初就对外宣布全面支持UEFI,这也促使了众多主板厂商纷纷转投UEFI,并将此作为主板的标准配置之一。#UEFI规范的主要组件和功能1.EFI系统分区(ESP-EFI System Partition)EFI系统分区必须为FAT格式的变种(包括 FAT12、FAT16 和 FAT32),用于存放UEFI引导程序和配置数据。单个硬盘可存在多个EFI分区,但通常只创建一个,容量大小取决于系统需求,庚老师的习惯是创建1G~2G,以后可能需要分配更大的分区。ESP中存储引导加载程序可以被UEFI固件扫描到。EFI系统分区是在安装操作系统的时候指定的。2.UEFI固件UEFI固件是主板或设备上的固件代码,负责初始化硬件、加载引导程序(boot loader)。UEFI固件会动态扫描ESP中的引导程序,生成可选择的启动项,用户可以在UEFI界面中添加、删除、排序启动项。3.UEFI驱动UEFI驱动遵循UEFI驱动模型,支持动态加载,如USB驱动、网卡驱动,无需在启动阶段固化在固件,可以存放在EFI系统分区中。#UEFI比BIOS强大的原因UEFI之所以比BIOS强大,是因为UEFI本身已经相当于一个微型操作系统,其带来的便利之处在于UEFI已具备文件系统的支持,它能够直接读取FAT分区中的文件,相比于BIOS只能读取磁盘的第一个扇区来说,UEFI是直接操作文件系统的。可根据UEFI标准,开发出直接在UEFI下运行的应用程序,这类程序文件通常以efi结尾。既然UEFI可以直接识别FAT分区中的文件,又有可直接在其中运行的应用程序。那么完全可以将Windows安装程序做成efi类型应用程序,然后把它放到任意fat分区中直接运行即可,如此一来安装Windows操作系统这件过去看上去稍微有点复杂的事情突然就变非常简单了,就像在Windows下打开浏览器一样简单。而事实上,也就是这么一回事。#UEFI启动流程UEFI的启动流程比BIOS简单的多,设备加电,UEFI平台(系统)启动,UEFI平台读取磁盘中的efi应用,加载操作系统。就是这么平平无奇,你的UEFI本身就算是一个操作系统,只不过这个操作系统是你购买了主板之后就自带的操作系统,主板供应商已经在主板上把这个UEFI系统准备好了,这个UEFI系统可以直接读取你磁盘中的efi分区中的加载程序(boot loader),然后加载程序加载完内核,后续的事情就由内核接管了,简单吧,没错,就是这么简单,没有任何花里胡哨的东西。

#MBR分区和GPT分区操作系统启动中最重要的部分其实是找到boot loader,如果没有找到boot loader,那么再牛逼的固件,都无法加载操作系统。从前面的学习我们也了解到了BIOS和UEFI找到boot loader的方法似乎不太一样,没错,去掉似乎,就是不一样。BIOS是找磁盘中的MBR(1个扇区),然后找到其中的boot loader,但是UEFI是直接找EFI文件系统中的boot loader,这肯定不一样啊。所以磁盘中是有MBR还是EFI分区就决定了你到底要选择什么固件去找到boot loader,现在很难在世面上找到纯BIOS固件的主板了,所谓的BIOS固件主板,都是UEFI兼容BIOS的模式。那么既然都是UEFI了,就需要注意一个事情了,纯种的UEFI只能通过找到EFi分区来找到加载程序,进而加载操作系统,如果你的磁盘中没有efi分区,那么你自然就无法加载操作系统了。然后你可能就想了,那就安装操作系统的时候创建efi分区不就行了?没错,现在的操作系统安装都是要在磁盘中创建efi分区的,比如windows你安装的时候就会自动创建EFI分区,由于Windows系统是闭源的,所以这是个强制选项。但是当你安装Linux的时候你是可以选择是否创建efi分区的,当然,如果你不创建efi分区,那么你的操作系统是无法安装的,我们当时在安装linux系统的时候选择的是自动分区,所以默认就创建了efi分区。我们已经知道了efi分区很重要了吧,efi分区是UEFI是否能找到操作系统的关键,但是你思考一下就会知道,其实早期在BIOS作为唯一固件的时代是没有efi分区这个概念的,有的只是MBR,那么问题来了,MBR是怎么来的?在BIOS时期MBR的重要性不言而喻,所以创建BMR就很重要了,MBR实在磁盘上的,所以其实在对磁盘进行分区的时候就会带上MBR,但是采用的分区方法就是MBR分区表,注意MBR和MBR分区是两个东西,只有采用了MBR分区形式的磁盘才会有MBR。这就导致了BIOS时代其实所有的安装了操作系统的磁盘都采用了MBR的分区。MBR分区有很多的问题,比如只能有4个主分区,磁盘容量不能超过2T等问题,但是在当时那个年代,4个主分区依然够用,超过2T的磁盘更是不敢想象的事情,所以就任由MBR一直处于那个状态持续了20多年。
3、操作系统启动流程的本质流程
实际上PC的启动固件的引导流程从IBM PC机诞生第一天起,就没有本质改变过。如果我们透过各种固件启动等复杂的术语幕后隐藏的本质,就会发现无论传统BIOS还是UEFI,阳光之下没有什么新鲜的东西,启动本身无外乎三个步骤:1.Rom Stage在这个阶段没有内存,需要在ROM上运行代码。这时因为没有内存,没有C语言运行需要的栈空间,开始往往是汇编语言,直接在ROM空间上运行。在找到个临时空间(Cache空间用作RAM,Cache As Ram, CAR)后,C语言终于可以粉墨登场了,后期用C语言初始化内存和为这个目的需要做的一切服务。2.Ram Stage在经过ROM阶段的困难情况后,我们终于有了可以大展拳脚的内存,很多额外需要大内存的东西可以开始运行了。在这时我们开始进行初始化芯片组、CPU、主板模块等核心过程。3.Find something to boot Stage终于要进入正题了,需要启动,我们找到启动设备。就要枚举设备,发现启动设备,并把启动设备之前需要依赖的节点统统打通。然后开始移交工作,Windows或者Linux的时代开始。传统BIOS和UEFI的启动过程在剥去了术语后,主干的三个步骤从来没有变化过。
4、当代操作系统的启动流程
现代计算机是软件与硬件的复杂组合,从接通电源开始,到可以登录到系统中,需要大量的软件和硬件的配合。这节课学习一下Linux操作系统在启动过程中所涉及的任务,虚拟机的流程也是大致相同的,但是某些与硬件相关的步骤是由虚拟机的相关程序在软件中处理的。 1. 接通电源和开机自检(POST) 系统固件(UEFI或BIOS)初始化,运行开机自检,并初始化部分硬件。该过程主要对计算机各种硬件设备进行检测,如CPU、内存、主板、硬盘、CMOS芯片等。如果出现致命故障则停机,并且由于初始化过程还没完成,所以不会出现任何提示信号;如果出现一般故障则会发出声音等提示信号,等待故障清除;若未出现故障,加电自检完成。 2. 系统固件搜索可启动设备 启动设备可能是UEFI启动固件中配置的,也可能是按照BIOS中配置的顺序搜索所有磁盘上的主启动记录(MBR或GPT)。 # #MBR 开机自检完成后,CPU首先读取位于EEPROM中的BIOS程序,按照BIOS中设定的启动次序(Boot Sequence)逐一查找可启动设备。找到可启动的设备后,去该设备的第一个扇区中读取MBR。 MBR存在于可启动磁盘的0磁道0扇区,占用512字节,它主要用来告诉计算机从选定的可启动设备的哪个分区来加载引导加载程序(Boot loader)。MBR中存在如下内容: (1)Boot Loader:占用446字节,存储有操作系统(OS)相关信息,如操作系统名称、操作系统内核位置等,它的主要功能是加载内核到内存中运行。 (2)Partition Table 分区表:占用64字节,每个主分区占用16字节(这就是一块硬盘只能有4个主分区的原因) (3)分区表有效性标记占用2字节 CPU将MBR读取至内存,运行GRUB(Boot Loader常用的有GRUB和LILO两种,现在常用的是GRUB),GRUB会把内核加载到内存去执行。 #GPT UEFI 固件会读取 EFI 系统分区(ESP)中的引导程序(如EFI/GRUB/grubx64.efi),无需 MBR 参与。 此过程中,UEFI 充当了“第一阶段 Bootloader”,直接通过GUID定位并执行 ESP 中的 GRUB。 UEFI固件启动 → 扫描所有磁盘 → 查找分区类型GUID为ESP的分区 → 在ESP分区的EFI/目录下寻找引导程序 → 执行找到的.efi文件 3.boot loader 系统固件会从MBR中读取启动加载器,然后将控制权交给启动加载器,在现在的Linux发行版本中,启动加载器为GRUB2 GRUB(GRand Unified Bootloader) 是最常用的 Linux 引导程序。 GRUB 阶段 1:从 MBR 或 ESP 中加载 GRUB 的第一阶段代码。 GRUB 阶段 3:加载选定的内核和初始化内存盘(initrd)。 4.Kernel(内核)启动 内核加载:GRUB 将 Linux 内核(通常是 /boot/vmlinuz)和初始化内存盘(initrd)加载到内存中。 内核初始化: 硬件检测:内核会检测系统硬件并加载相应的驱动程序。 初始化进程:内核启动后,会创建第一个用户空间进程,通常是 init 或 systemd。 GRUB把内核加载到内存后展开并运行, 此时GRUB的任务已经完成,接下来内核将会接管并完成 探测硬件->加载驱动->挂载根文件系统->切换至根文件系统(rootfs)->运行/sbin/init完成系统初始化。但是,问题来了,要访问根文件系统必须要加载根文件系统所在的设备,而这时根文件系统又没有挂载,要挂载根文件系统有需要根文件系统的驱动程序,这是一个典型的先有鸡先有蛋的问题啊!为解决这个问题,GRUB在加载内核同时,也把initrd加载到内存中并运行,那么initrd又起到了什么作用哪? initrd文件其实是一个虚拟的根文件系统,里面有bin、lib、lib64、sys、var、etc、sysroot、 dev、proc、tmp等根目录,它的功能就是将内核与真正的根建立联系,内核通过它加载根文件系统的驱动程序,然后以读写方式挂载根文件系统,至此,内核加载完成。(我们后续讲解linux密码破解也是进入到这个文件系统,挂载真正的根分区,然后修改密码,当然为了防止破解密码,也可以为grub配置密码) 内核加载进内存运行并以读写方式挂载完根文件系统后,执行第一个用户进程。 5.加载系统的第一个进程 Systemd(现代 Linux 系统的默认初始化系统)或 SysVinit(传统的初始化系统)负责启动用户空间的进程和服务。 6. 用户登录 登录管理器 Systemd 或 SysVinit 启动登录管理器,允许用户输入用户名和密码进行登录。登录后,系统会启动用户会话,加载用户配置文件(如 .bashrc、.profile 等),并启动用户的应用程序和服务。