Linux操作系统开机启动的过程--使用GRUB引导

  • Linux操作系统开机启动的过程–使用GRUB引导

    在Linux操作系统中,开机启动过程涉及多个关键步骤,从主板的启动方式到Linux内核的加载,再到用户空间进程的初始化。这篇文章详细探讨了两种主流的主板启动方式( [[GRUB]] 和[[UEFI]]),以及它们如何引导[[GRUB]]来加载[[Linux内核]]。随后,我们会深入讨论GRUB加载内核后,Linux内核如何初始化根文件系统以及使用systemdSysVinit完成系统的启动。


  • 2种不同的主板启动方式: BIOS和UEFI

    目前,计算机硬件主要使用两种启动固件:BIOS(Basic Input/Output System)和UEFI(Unified Extensible Firmware Interface)。这两种方式在加载GRUB和启动Linux系统时具有显著差异。

  • BIOS:传统的BIOS固件通过读取主引导记录(MBR)来查找启动代码。BIOS启动时会读取MBR的前512字节(其中包括启动引导扇区),此扇区中包含的代码指向存储设备的引导加载程序。

  • UEFI:与BIOS不同,UEFI引导模式依赖于EFI分区(ESP),该分区是一个独立的FAT文件系统分区,通常标记为“EFI System Partition”。UEFI能够直接读取存储设备上的GRUB EFI文件,允许更灵活的启动配置和更多的存储空间。

    从这两种方式加载GRUB之后,GRUB引导Linux内核的流程则基本一致,差别主要体现在引导时的初始加载机制和存储格式上。


  • 通过BIOS加载GRUB

    在BIOS模式下,启动过程分为多个细致的阶段,从系统上电到启动GRUB再到引导Linux内核,每一步都有其特定的流程和角色。下面将详细描述这些阶段:

    1. BIOS上电自检(POST):系统通电后,BIOS(Basic Input/Output System)固件首先会执行电源自检(Power-On Self Test,POST)流程。POST初始化CPU、内存、图形卡、硬盘、键盘和其他外设,确保硬件处于正常状态。POST完成后,BIOS固件会定位系统的引导设备(通常在BIOS设置中指定),如硬盘、光盘或USB驱动器,并尝试从该设备启动操作系统。
    1. 读取MBR:一旦BIOS确认引导设备(例如硬盘),它会尝试读取该设备的第一个扇区(即主引导记录,MBR)。MBR占据硬盘的前512字节,其中包含了以下关键内容:
    • 启动引导程序:MBR的前446字节包含一小段启动引导代码,它负责识别并启动操作系统的引导程序。BIOS会将该部分代码加载到内存中并执行。
    • 分区表:MBR中接下来的64字节为分区表,存储硬盘上的分区信息。
    • 魔数:最后2字节是一个魔数(55aa),用于验证MBR的完整性。如果魔数无效,BIOS会判断MBR已损坏,从而无法继续引导。
    1. 加载GRUB阶段1:MBR中的启动引导代码包含的程序十分简单,大小限制在446字节左右,因此通常只包含最基础的指令。在GRUB的多阶段设计中,这一阶段的代码被称为GRUB的第一阶段(stage 1)。此时,MBR中的代码将加载并启动GRUB的下一阶段。由于空间有限,stage 1代码只负责查找并加载更大的stage 1.5或stage 2文件。
    1. GRUB的阶段1.5:GRUB通常还包含一个称为stage 1.5的中间阶段,位于MBR之后的若干扇区(称为“引导扇区”或MBR gap)中。stage 1.5在加载时会尝试加载必要的文件系统驱动,使GRUB能够访问文件系统,便于加载配置文件和更大的引导程序。如果系统支持并安装了stage 1.5阶段代码,GRUB可以在此阶段加载其配置文件和必要的文件系统模块。
    1. 加载GRUB阶段2:一旦stage 1.5完成引导准备,GRUB将继续加载stage 2阶段代码(完整的GRUB程序)。在stage 2中,GRUB开始显示用户可见的启动菜单。此阶段不仅可以从文件系统中加载内核映像文件,还支持内核参数设置和引导配置。
    1. 进入GRUB菜单:在GRUB的阶段2加载后,用户会看到GRUB启动菜单界面,提供多项选择:
    • 内核选项:用户可以选择不同的内核版本,或者通过菜单条目指定内核参数,例如单用户模式或恢复模式。
    • 高级配置:用户还可以手动编辑GRUB配置或进入命令行模式以调整启动配置。
    • 内核启动:选择启动项后,GRUB通过boot命令加载并启动内核,同时传递内核启动参数(如根文件系统路径等)。

  • 通过UEFI加载GRUB

    相比于BIOS引导,UEFI引导流程更加灵活,也更适合现代硬件设备。UEFI使用EFI系统分区(ESP)来管理和加载启动文件,不再依赖MBR格式,从而支持更大的硬盘容量和更多分区数量。

    1. UEFI固件初始化:系统上电后,UEFI固件执行硬件自检和初始化(类似于BIOS的POST流程)。在硬件初始化完成后,UEFI固件会自动查找并加载EFI系统分区(ESP)中的启动文件。ESP分区是一个独立的FAT文件系统分区,通常包含各种启动项文件和配置文件。UEFI会根据配置或默认路径查找启动项,优先加载ESP分区中的可执行文件。
    2. 加载GRUB EFI文件:在ESP分区中,UEFI能够直接读取和执行可执行的EFI文件,如grubx64.efi。该文件是GRUB为UEFI引导而编译的可执行程序,通常位于/EFI/boot/目录下。UEFI加载并执行grubx64.efi文件后,将控制权移交给GRUB EFI文件,从而初始化GRUB引导加载器。在UEFI设置中,用户可以手动配置启动顺序、指定GRUB EFI文件的路径,甚至选择不同的操作系统引导项。
    3. GRUB的初始化与进入启动菜单:GRUB EFI文件加载后,GRUB引导加载器开始执行其初始化代码,并显示启动菜单。此时,用户可以通过菜单界面选择操作系统,指定Linux内核和内核参数,或进入GRUB命令行模式手动输入引导配置。后面就与BIOS一样了。
    4. GRUB加载速度与扩展支持:由于UEFI支持读取FAT文件系统并直接访问ESP分区,GRUB的加载速度相比传统BIOS模式有所提升。此外,UEFI模式下GRUB的启动选项和配置项更多,可以处理超过2TB的硬盘分区,支持更多文件系统格式,使其适用于现代大型存储设备。

  • GRUB加载Linux内核

    在BIOS或UEFI加载完成后,GRUB的主要任务是启动Linux内核并传递必要的启动参数。这个过程可以通过grub.cfg配置文件来了解具体加载步骤。grub.cfg通常位于/boot/grub/boot/efi/EFI/<distro>/目录中,负责定义GRUB的启动项、内核路径和其他配置项。下面详细说明GRUB加载Linux内核的过程。

    1. 加载启动配置(grub.cfg):GRUB引导时会读取grub.cfg文件,该文件包含系统的启动配置。每个启动项通常定义如下指令:
    • menuentry:定义启动菜单项的名称。此处包含不同操作系统或内核版本的描述。例如:
      menuentry 'Ubuntu 20.04 LTS' {
          linux   /boot/vmlinuz-5.4.0-42-generic root=UUID=<UUID> ro quiet splash 
          initrd  /boot/initrd.img-5.4.0-42-generic
      }
      
      
    • linux /vmlinuz-:指定内核文件的路径和版本。此行将加载具体的Linux内核映像文件,并可以在这一行中附加启动参数。
    • initrd /initrd.img-:指定临时根文件系统的路径(如initrd或initramfs),提供启动过程中需要的模块和驱动程序。
    1. 内核参数传递:在GRUB菜单中,每个menuentry的配置中通常包括linux指令,这一行用于加载Linux内核映像并指定启动参数。例如:
    • linux /vmlinuz-5.4.0-42-generic root=/dev/sda1 ro quiet splash
      
    • root:指定根文件系统的位置(如/dev/sda1),告知内核应挂载哪个设备为根文件系统。

    • ro:表示根文件系统在启动时以只读模式挂载。

    • quietsplash:这些参数用于控制启动时的信息输出(如静音启动和加载启动画面)。

      这些内核参数在将控制权交给内核时传递给内核,以帮助内核初始化和加载正确的配置。

    1. 加载initrd/initramfs:在一些系统中,GRUB还需要加载一个临时根文件系统initrd(或initramfs)。该文件系统通常指定在initrd指令中,例如:
    • initrd /initrd.img-5.4.0-42-generic
      
    • initrd或initramfs文件中包含了启动所需的驱动程序和模块,用于识别并初始化硬件组件(如文件系统、磁盘驱动器等)。
    • initrd/initramfs文件可以帮助内核加载必要的模块,例如硬件驱动和网络配置,确保在系统最终加载根文件系统之前已经完成关键的硬件初始化。
    1. 启动内核:一旦内核映像和initrd/initramfs被加载完毕,GRUB通过boot命令启动内核。这一命令将控制权移交给内核,从而进入内核的初始化流程:
    • boot
      
      在此阶段,内核会从GRUB接收控制权并根据传递的参数进行启动配置。在内核初始化过程中,会挂载根文件系统,加载必要的设备驱动,初始化系统管理进程init(通常为systemdSysVinit),随后逐步启动用户空间环境。

  • Linux内核加载根文件系统

    当GRUB将控制权移交给Linux内核后,内核开始执行自检和初始化过程,并完成根文件系统的挂载和初始化。这个过程中包括了从硬件检测、驱动加载到启动第一个用户进程init的多个步骤。

    1. 驱动加载与初始化
    • 初始化硬件驱动:在内核启动初期,内核会从initrd或initramfs加载预定义的硬件驱动和模块。initramfs提供了一个临时的内存根文件系统,包含启动所需的关键驱动和模块,如存储设备、文件系统和网络接口等硬件模块。
    • 模块自动检测:现代内核支持模块自动检测(如udev服务),会根据当前系统硬件状况动态加载所需的内核模块。这样可以在尽量减少冗余模块加载的同时,确保对硬件的全面支持。
    • 初始化设备节点:加载硬件驱动后,内核通过/dev目录创建设备节点,设备节点使用户空间的程序可以访问硬件设备。
    1. 挂载根文件系统
    • 找到根分区:在启动参数中,GRUB会指定根文件系统的位置,通常通过root=UUID=<UUID>root=/dev/sdX的方式,帮助内核找到对应的根分区。内核在此阶段会依据该参数确定具体的分区,并准备挂载根文件系统。
    • 切换根文件系统:一旦识别并加载根文件系统,内核将从临时文件系统(initramfs)切换到真实的根文件系统,并将其设定为系统的主要操作环境。此时,内核会使用真实的根文件系统覆盖原来的initramfs根文件系统,执行pivot_root操作,使系统正式进入独立的根文件系统环境。
    • 卸载initramfs:切换完成后,内核会卸载并释放initramfs的资源,以节省内存并确保系统只使用一个根文件系统。
    1. 启动init进程
    • 查找init进程:内核完成根文件系统的挂载后,会启动第一个用户空间进程,即/sbin/initinit进程是所有用户空间进程的祖先,被赋予PID 1。
    • 初始化系统管理(systemd或SysVinit)
      • 如果使用systemd/sbin/init通常是一个指向systemd的符号链接。systemd负责启动和管理系统的服务,依赖系统配置启动目标(如multi-user.targetgraphical.target)定义的服务列表来管理启动顺序。
      • 如果使用传统的SysVinit,则/sbin/init执行SysVinit脚本,在/etc/inittab文件中根据不同的运行级别启动不同的服务。
    • 加载用户空间环境init启动后,系统正式进入用户空间环境,此时init会启动各种用户服务、后台进程以及登录服务。接着,系统进入正常操作状态,用户可以开始交互式操作系统。

  • systemd方式启动

    在现代Linux发行版中,systemd是主要的系统和服务管理工具,负责系统启动、服务管理、系统资源配置和日志记录等功能。相比传统的SysVinit,systemd在启动流程中引入了并行化服务加载和更细致的依赖管理,从而显著提升了启动效率。以下是systemd启动Linux系统的主要步骤:

    1. 加载启动目标(Target)
    • systemd的启动目标类似于传统SysVinit的运行级别(runlevel),通过定义不同的启动目标来控制系统的启动模式。常见的目标有:
    • multi-user.target:加载命令行模式,适合多用户环境但不启动图形界面。通常等同于SysVinit的“运行级别3”。
    • graphical.target:启动图形界面(如GNOME、KDE等),适用于桌面环境用户,相当于传统的“运行级别5”。
    • rescue.target:启动到救援模式,通常仅加载基础服务和系统命令行,用于系统维护。
    • emergency.target:仅加载最少的服务和shell,用于系统修复和紧急情况。
    • 当系统启动时,systemd根据配置文件(如/etc/systemd/system/default.target)指定的默认启动目标,决定进入的系统模式,并根据目标加载必要的服务和依赖进程。用户也可以在引导菜单中通过参数(如systemd.unit=multi-user.target)临时指定启动目标。
    1. 并行加载服务与依赖解析
    • 并行服务启动systemd的一个显著特性是支持并行启动服务。传统的SysVinit采用顺序加载,导致系统启动时需要等待服务依次启动,而systemd能够分析服务的依赖关系,按需并行加载,提高启动速度。例如,网络服务可以与日志服务并行加载,而不必依赖特定的顺序。

    • 依赖解析systemd通过依赖链管理服务启动顺序。每个服务单元(Unit)文件可以包含启动前的依赖项(RequiresAfter),systemd会根据这些依赖关系决定启动顺序。例如,network.service可能会在sshd.service之前启动,以确保SSH服务有网络支持。

      单元类型包括服务(service)、挂载点(mount)、设备(device)、路径(path)、socket等。systemd会根据这些单元文件的依赖关系,按最优顺序加载所需服务和挂载文件系统,确保启动的效率和可靠性。

    1. 启动用户空间并进入登录界面
    • 服务就绪检测:当所有核心系统级服务和依赖项被加载后,systemd会检查是否满足启动目标的所有条件,以确保系统达到稳定状态。例如,在graphical.target模式下,需要等待图形服务(如gdm.service)启动完毕。
    • 启动显示管理器和登录界面:在桌面环境中,systemd会启动显示管理器(如GDM、LightDM或SDDM),以提供图形化登录界面。对于命令行模式,systemd则会启动getty服务,提供控制台登录提示符。
    • 用户会话管理:当用户登录后,systemd启动一个单独的用户会话管理实例(systemd --user),管理用户会话中的服务和应用程序。用户会话的独立管理有助于资源隔离、自动重启崩溃的用户级服务,并为多用户提供稳定的环境。

  • SysVinit方式启动

    在较老版本的Linux系统和经典发行版中,SysVinit是主要的初始化系统。它通过定义运行级别和依次执行启动脚本来控制系统启动。SysVinit启动过程较为简单,但缺乏现代systemd的并行和依赖管理能力,因此启动速度和灵活性有限。以下是SysVinit的启动流程:

    1. 加载运行级别(Runlevel)
      SysVinit通过/etc/inittab文件来配置系统的启动模式,每个运行级别(runlevel)定义了一组特定的启动服务和资源限制,允许系统在不同环境下启动。常见的运行级别包括:
    • 0:关机
    • 1:单用户模式(用于维护和故障排查,不启动网络和多用户服务)
    • 2:多用户模式(不启动网络文件系统)
    • 3:完整多用户模式,启用网络支持
    • 5:图形用户界面模式,通常是桌面环境的运行级别
    • 6:重启
    • SysVinit启动时会从/etc/inittab中读取默认的运行级别,并根据该级别加载相应的服务。例如,默认运行级别为3(多用户模式),SysVinit会进入对应的多用户环境,并加载必要的网络服务。
    1. 顺序启动服务
    • SysVinit的核心是按照预定义顺序执行启动脚本,启动流程较为严格的顺序控制。启动服务的具体流程如下:
    • 启动脚本位置:每个运行级别对应一个目录(如/etc/rc.d/rc3.d),该目录下包含一系列按字母或数字顺序命名的启动脚本符号链接。文件名通常以SK开头,后接数字序号,如S10networkS20sshd,分别表示启动网络和SSH服务。
    • 顺序执行脚本:当进入某个运行级别时,SysVinit会按照编号顺序执行脚本。例如,在rc3.d目录下,文件名S10network表示网络服务将在编号较低的服务(如S05serviceA)之后启动,而在S20sshd之后启动的服务则需等待SSH服务准备就绪。
    • 服务停止:若切换到不同的运行级别(如从3切换到0关机),SysVinit会执行以K开头的脚本,按编号顺序依次关闭不再需要的服务,如K20sshd用于停止SSH服务。
    1. 进入用户空间
    • 启动登录界面:服务加载完成后,SysVinit会根据运行级别决定是否启动控制台或图形登录界面。在多用户模式(运行级别3),SysVinit会启动控制台登录进程(getty),等待用户通过终端登录。在图形模式(运行级别5),则启动图形显示管理器(如GDM、LightDM)以提供桌面环境的登录界面。
    • 用户会话:用户登录后,系统进入用户空间,所有的用户进程在内核的支持下独立运行。此时,用户可以启动应用程序和服务,开始正常的操作。

  • 总结

    本文探讨了Linux系统从上电启动到用户空间启动的详细过程,涵盖BIOS和UEFI两种不同的固件启动方式、GRUB引导过程、内核和根文件系统的加载以及systemdSysVinit的初始化流程。理解这些启动步骤不仅能帮助Linux系统管理员更好地排查启动问题,也为深入学习Linux内核和系统架构奠定了基础。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值