ARTICLE DETAIL

资讯详情

深耕网站SEO优化与搜索引擎排名提升的一线实战洞察。

Linux系统启动全流程解析:从BIOS/UEFI到systemd的完整指南

Linux系统启动全流程解析:从BIOS/UEFI到systemd的完整指南 1. 从按下电源到屏幕亮起一次开机旅程的宏观图景每次按下电脑的电源键看着屏幕上开始滚动那些熟悉的字符你有没有想过这台机器究竟是如何从一堆冰冷的硬件一步步苏醒最终变成一个可以让你敲命令、跑程序的完整操作系统的对于Linux用户尤其是运维、开发或者任何想深入理解系统底层的人来说搞懂开机启动流程就像拿到了系统的“地图”。它不仅是面试时的经典考题更是你排查“系统起不来”、“服务没启动”、“卡在某个黑屏界面”这类问题的根本依据。今天我就结合自己这些年折腾服务器和桌面的经验带你走一遍Linux系统从通电到登录提示符出现的完整旅程我会尽量把每个阶段“为什么这么做”以及“可能在哪里翻车”讲清楚。整个流程可以粗略地分为几个大的阶段首先是硬件自己上电自检和初始化这个阶段操作系统还没介入然后一个小而精的引导程序被加载它的唯一任务就是找到并启动真正的操作系统内核内核接过控制权后开始初始化计算机的核心环境并挂载根文件系统最后由用户空间的初始化进程拉起所有我们需要的系统服务和应用。听起来步骤清晰但魔鬼藏在细节里。无论是传统的BIOSMBR组合还是现代的UEFIGPT组合亦或是systemd、SysV init等不同的初始化系统都会让这条路径产生微妙而重要的变化。我们这就开始。2. 固件初始化阶段BIOS与UEFI的战场当你按下电源按钮CPU的复位引脚被触发从一个预设的物理地址对于x86架构是0xFFFF0开始执行第一条指令。这个地址指向主板上一块特殊的ROM芯片——这就是固件Firmware的地盘。目前主流的固件有两种传统的BIOS和现代的UEFI。理解它们的区别是理解后续所有步骤的基础。BIOS的工作方式相对“古老”和直接。它进行完基础的硬件自检后就会按照你在BIOS设置里定义的顺序比如先U盘、再硬盘、再网络去每个存储设备的第一个扇区512字节寻找一段特殊的代码——主引导记录。这里有个关键点BIOS本身不认识文件系统。它只会傻傻地读取硬盘的0柱面、0磁头、1扇区也就是第一个512字节。因此引导程序必须把自己压缩在这512字节内这极大地限制了引导程序的复杂度和功能。UEFI则是一个更先进的微型操作系统。它本身支持文件系统和驱动因此不再需要去搜索一个特定的扇区。UEFI固件会直接读取一个特殊的分区——EFI系统分区。这个分区通常是FAT32格式UEFI固件能直接识别并遍历其中的文件。启动时UEFI会根据其内部变量NVRAM中存储的启动项直接去ESP分区里找到对应的.efi可执行文件并运行它。这个.efi文件就是我们的引导程序比如grubx64.efi。因为不受512字节限制UEFI引导程序可以做得非常强大和复杂。注意很多人在新硬件上安装Linux时会遇到“无法找到可引导设备”的错误这十有八九是因为安装介质是BIOS模式MBR格式制作的而你的电脑在UEFI模式下运行。或者反过来。确保安装介质的模式UEFI还是Legacy与你的BIOS/UEFI设置一致是成功的第一步。那么如何知道你的系统是用哪种方式启动的呢一个简单的方法是检查是否存在/sys/firmware/efi目录。如果存在你就是UEFI启动如果不存在你很可能就是传统的BIOS启动。另一个方法是使用efibootmgr命令如果它能列出启动项那肯定是UEFI环境。# 检查是否为UEFI启动 ls /sys/firmware/efi # 查看UEFI启动项 (仅UEFI模式下有效) sudo efibootmgr -v对于“老显卡改BIOS支持UEFI启动”这类网络热词其背景是一些较老的显卡其显卡BIOSVBIOS不支持UEFI的GOP协议只支持传统的BIOS的VBIOS协议。当主板运行在纯UEFI模式关闭了CSM兼容性支持模块时就无法初始化这块老显卡导致黑屏。所谓的“改BIOS”就是给老显卡的VBIOS添加UEFI GOP模块使其能在纯UEFI环境下被识别。这是一个高风险操作普通用户不建议尝试。3. 引导加载程序GRUB2如何找到内核固件找到了引导程序并把控制权交给了它。在Linux世界这个引导程序的绝对霸主是GRUB2。它的任务很明确加载操作系统内核镜像和初始内存盘然后把控制权交给内核。但这个过程并不简单。在BIOSMBR的世界里由于MBR只有512字节根本放不下完整的GRUB2。所以采用了分阶段加载的策略Stage 1: 这512字节的MBR里前446字节是引导代码它唯一的作用是找到并加载Stage 1.5。Stage 1.5: 位于MBR之后的扇区大概是第2到第63扇区。这个阶段包含了识别常见文件系统如ext4 xfs的驱动。因为Stage 1的代码太简单不认识文件系统而Stage 1.5认识。它就能去文件系统里找到Stage 2了。Stage 2: 这才是GRUB2的主体通常存放在/boot/grub2/目录下。它会读取配置文件如grub.cfg显示那个我们熟悉的图形化或命令行菜单让你选择要启动的内核版本。在UEFIGPT的世界里事情就简单多了。GRUB2的主体直接被编译成一个.efi可执行文件如grubx64.efi存放在ESP分区里比如/EFI/ubuntu/。UEFI固件直接加载并执行这个文件它自己就包含了所有需要的功能不需要分阶段。GRUB2的核心工作是解析其配置文件grub.cfg。这个文件通常不是直接编辑的而是由grub2-mkconfig命令根据/etc/default/grub和/etc/grub.d/目录下的脚本自动生成。我们来看看一个典型的grub.cfg中一个启动项的关键部分menuentry Ubuntu --class ubuntu --class gnu-linux --class gnu --class os $menuentry_id_option gnulinux-simple-xxxxx { recordfail load_video gfxmode $linux_gfx_mode insmod gzio insmod part_gpt insmod ext2 set roothd0,gpt2 linux /boot/vmlinuz-5.4.0-xx-generic rootUUIDxxxx ro quiet splash initrd /boot/initrd.img-5.4.0-xx-generic }set roothd0,gpt2: 告诉GRUB内核文件在哪个设备哪个分区。hd0表示第一块硬盘gpt2表示GPT分区表下的第二个分区。linux /boot/vmlinuz-... rootUUIDxxxx ...: 这是最关键的一行。linux命令加载内核镜像文件vmlinuz并将后续参数作为内核启动参数传递给内核。其中rootUUIDxxxx指定了根文件系统所在分区的UUID这是内核接下来要挂载为“/”的地方。ro表示先以只读方式挂载后续由初始化进程重新挂载为读写quiet splash是控制启动画面的参数。initrd /boot/initrd.img-...: 加载初始内存盘。这个文件至关重要我们下一节详细讲。实操心得很多时候系统启动失败卡在grub命令行界面就是因为grub.cfg损坏或指向的root设备不对。此时你可以在grub命令行下手动输入上述set root、linux、initrd三条命令来临时引导系统。进入系统后再修复GRUB配置。记住ls命令在GRUB命令行下可以列出设备帮你找到正确的分区。4. 内核初始化与initrd的桥梁作用GRUB将控制权、内核镜像vmlinuz以及初始内存盘initrd或initramfs加载到内存后就功成身退了。内核开始解压自己并执行。但这里马上遇到一个问题内核镜像为了保持精简默认只包含了访问根文件系统所必须的驱动比如你编译内核时选定的文件系统驱动、磁盘控制器驱动。而你的根文件系统可能在一个非常复杂的存储方案上比如软RAID、LVM逻辑卷、加密分区或者网络挂载。内核在启动初期根本没有加载这些复杂存储方案所需的驱动和工具。这就产生了一个“先有鸡还是先有蛋”的矛盾要挂载根文件系统需要驱动和工具但这些驱动和工具又存放在根文件系统里。初始内存盘就是为了解决这个矛盾而生的。它是一个临时的根文件系统在真正的根文件系统被挂载之前被加载到内存中运行。你可以把它想象成一个装在内存里的“急救包”。这个急救包里包含了挂载真实根文件系统所需的所有驱动、内核模块、工具如cryptsetup用于解密lvm用于激活卷组nfs客户端用于网络挂载以及一个简单的脚本/init。内核启动的最后一步就是执行这个initrd中的/init脚本。这个脚本通常用BusyBox工具集写成它的任务非常明确初始化必要的设备如/dev。加载复杂存储方案所需的驱动模块从initrd自身加载。发现真正的根文件系统设备通过解析内核参数root可能涉及解密、激活LVM等操作。将真正的根文件系统挂载到/sysroot目录下。最后执行一个**switch_root**操作。这是一个关键动作它清理当前的内存环境将/sysroot切换为新的根目录/然后去新的根文件系统里执行/sbin/init程序现在是systemd或sysvinit。至此内核的使命完成用户空间的初始化进程开始接管。你可以通过查看/boot目录下的文件来了解你系统使用的initrd并使用lsinitramfs或dracut -l等工具来查看initrd里面具体包含了哪些模块和文件。# 查看initrd内容示例 (Ubuntu/Debian) lsinitramfs /boot/initrd.img-$(uname -r) | head -20 # 查看initrd内容示例 (RHEL/CentOS/Fedora) sudo dracut -l /boot/initramfs-$(uname -r).img踩坑记录我遇到过服务器重启后卡在“Loading initial ramdisk”之后提示找不到根设备。原因是在内核升级后新生成的initrd没有包含硬盘控制器如megaraid_sas的驱动。这是因为生成initrd的工具如update-initramfs或dracut在自动探测依赖时漏掉了。解决办法是手动将驱动模块名添加到配置中然后重新生成initrd。例如在Ubuntu上编辑/etc/initramfs-tools/modules文件加入megaraid_sas然后运行sudo update-initramfs -u -k all。这个坑告诉我们对于使用特殊硬件驱动的系统不能完全依赖自动化工具。5. 用户空间的起点systemd的崛起与统治当initrd的/init脚本执行switch_root后系统的根目录已经切换到了硬盘上真正的根文件系统。接下来系统会寻找并执行这个新根文件系统下的/sbin/init程序历史上这是PID为1的进程。在过去的十多年里大多数Linux发行版使用的是SysV init系统它依靠运行级别Runlevel和一堆放在/etc/rc.d/目录下的启动脚本来管理服务。然而现在几乎所有的现代主流发行版RHEL 7/8/9 CentOS 7/8 Fedora Ubuntu 16.04 Debian 8 openSUSE Arch等都切换到了systemd。/sbin/init现在通常是一个指向/lib/systemd/systemd的符号链接。systemd的目标不仅仅是初始化系统它更是一个庞大的系统和服务管理器负责管理从启动到关机的整个生命周期。为什么是systemd因为它解决了SysV init的几个核心痛点并行启动SysV init是严格的串行执行脚本速度慢。systemd通过依赖关系分析最大限度地并行启动服务显著加快启动速度。精确的依赖管理SysV init的依赖写在脚本注释里脆弱且不精确。systemd使用明确的单元文件Unit File定义服务、套接字、挂载点等并声明它们之间的依赖如RequiresAfter管理更清晰可靠。统一的管理接口使用systemctl命令可以统一地启动、停止、重启、查看状态、启用开机自启所有类型的单元体验一致。日志集成systemd自带日志系统journald所有进程的标准输出和错误都会被收集使用journalctl命令可以方便地查看再也不用到处找/var/log/messagessyslog了。systemd启动过程的核心是它的“目标”target。你可以把target理解为一组需要达到的状态的集合类似于SysV init的运行级别但更灵活。默认的启动目标通常是graphical.target带图形界面或multi-user.target多用户命令行。systemd的启动流程大致如下systemd作为PID 1进程启动。执行默认target例如multi-user.target及其所有依赖的target如basic.targetsysinit.target。每个target定义了需要启动的单元units。systemd根据单元文件中定义的依赖关系并行启动这些单元。单元包括服务.service、挂载点.mount、设备.device、套接字.socket等。例如它会先挂载/etc/fstab中列出的文件系统.mount然后启动网络服务network.service最后启动sshd.service等应用服务。你可以使用systemctl命令来查看系统启动耗时和各个服务的启动情况# 查看系统启动耗时 systemd-analyze blame # 查看启动流程的瀑布图 systemd-analyze critical-chain # 查看某个服务的详细状态 systemctl status sshd.service对于网络热词“trying to remove systemd which is protected”这通常发生在一些用户试图用apt remove systemd或yum remove systemd时。几乎所有的核心系统组件网络、日志、登录都深度依赖于systemd强行移除它会破坏系统的完整性所以包管理器会阻止这个操作。如果你真的不想用systemd比如想用openrc或runit那应该在安装发行版时就选择不支持systemd的衍生版如Devuan而不是在一个基于systemd的发行版上暴力移除它。6. 启动过程中的常见故障排查实战理解了流程排查问题就有了路线图。当你的Linux系统无法启动时不要慌根据卡住的阶段采用不同的方法。阶段一硬件/固件阶段故障现象按下电源键风扇转但屏幕无任何显示或者直接进入BIOS/UEFI设置界面。排查检查硬件连接内存、显卡、硬盘线是否插紧。听主板蜂鸣器报警声如果有对照主板手册判断。进入BIOS/UEFI设置检查启动设备顺序是否正确硬盘是否被识别。对于“BIOS中开启了虚拟化但任务管理器中显示已禁用”的问题这通常不是Linux启动问题而是Windows下的情况。可能的原因有a) 需要在BIOS中同时开启VT-x和VT-d或AMD-Vb) 某些品牌机如联想有“Windows Hypervisor Platform”选项也需要开启c) 保存BIOS设置后没有完全断电重启需拔掉电源线等待10秒。阶段二GRUB引导阶段故障现象屏幕黑屏左上角光标闪烁或者直接显示grub救援命令行或者报错“error: no such partition” “error: file/boot/grub/i386-pc/normal.modnot found”。排查GRUB菜单丢失通常是因为GRUB配置文件损坏或MBR/ESP分区中的GRUB核心文件损坏。解决方案是使用Live CD/USB启动挂载原系统的根分区和/boot分区如果需要然后chroot进去重新安装和配置GRUB。GRUB无法找到内核在grub命令行下使用ls命令列出所有磁盘和分区尝试手动设置root并加载内核。例如grub ls # 查看所有设备如(hd0) (hd0, gpt1)... grub set root(hd0,gpt2) # 假设你的/boot在第二个分区 grub linux /boot/vmlinuz-5.4.0-xx-generic root/dev/sda3 # 根据实际情况 grub initrd /boot/initrd.img-5.4.0-xx-generic grub boot如果能成功启动进入系统后务必修复GRUB配置。阶段三内核与initrd阶段故障现象卡在“Loading Linux x.x.x ...” “Loading initial ramdisk ...” 或内核panic提示“Kernel panic - not syncing: VFS: Unable to mount root fs on unknown-block(0,0)”。排查最常见原因是initrd镜像损坏或缺少必要的驱动如磁盘控制器、文件系统、RAID、LVM模块。可以在GRUB菜单编辑启动参数在linux行末尾添加init/bin/bash或rd.breakRHEL系来进入紧急shell检查/dev下是否有你的根磁盘设备如sda3dm-0等。如果进入紧急shell后能看到根设备但挂载失败可能是文件系统损坏。可以尝试fsck修复。如果根本看不到根设备那一定是initrd的问题。需要从Live环境chroot修复方法同GRUB修复重点是重新生成initrd。阶段四systemd初始化阶段故障现象系统卡在某个服务启动画面如“Started Update UTMP about System Runlevel Changes”或者直接进入紧急模式emergency mode提示“You are in emergency mode.”排查查看日志紧急模式下首先运行journalctl -xb查看从本次启动开始的详细日志错误信息通常会高亮显示。-x提供更多解释信息-b限定本次启动。检查依赖使用systemctl list-dependencies --reverse unit-name查看是哪个单元失败导致目标无法达成。常见原因/etc/fstab文件错误比如UUID写错或者网络文件系统NFS在网络未就绪时尝试挂载。可以在启动参数中添加nofail选项。文件系统检测fsck失败需要手动输入root密码进行修复。服务启动失败例如某个.service文件配置错误。可以在启动参数中加入systemd.unitmulti-user.target或rescue.target来跳过图形界面进入命令行模式然后使用systemctl status和journalctl -u unit-name来排查具体服务。对于“systemd 放启动脚本一会就服务关闭”这通常是因为服务进程自己退出了。检查服务单元文件中的Type配置应该是forking或simple并确保Restart策略设置正确如on-failure。更重要的是查看服务的日志journalctl -u your-service看进程退出前输出了什么错误信息。掌握这套从固件到服务的分层排查思路大部分启动问题都能找到突破口。核心就是看屏幕提示、查日志journalctl、在救援环境Live CD或紧急Shell下进行操作。7. 高级话题内核参数、启动目标与救援模式除了基本的流程还有一些高级技巧可以让你更自如地控制系统启动。内核启动参数在GRUB菜单界面按e键可以编辑当前启动项。在linux开头的行末尾你可以添加或修改参数。这些参数直接影响内核和systemd的行为。single或1: 直接进入单用户模式救援模式获得一个root shell用于系统修复。systemd.unitrescue.target: 让systemd启动到救援目标类似单用户模式但更干净。systemd.unitmulti-user.target: 跳过图形界面直接进入命令行多用户模式。quiet和splash: 分别控制是否显示详细启动信息和启动动画。删除它们可以看到详细的启动过程便于调试。nomodeset: 一个非常有用的参数告诉内核在启动阶段不要设置显卡显示模式。对于某些显卡尤其是NVIDIA独显驱动兼容性问题导致的黑屏、花屏加上这个参数往往能让你先进入系统然后再安装合适的驱动。root/dev/sdXY或rootUUIDxxx: 手动指定根文件系统设备覆盖GRUB配置中的设置。修改默认启动目标如果你想让系统默认启动到命令行界面节省资源适合服务器可以这样做sudo systemctl set-default multi-user.target要改回图形界面sudo systemctl set-default graphical.target使用救援模式Recovery Mode很多发行版在GRUB菜单里提供了一个“Recovery Mode”选项。这个选项通常会以只读方式挂载根文件系统。启动一个最小化的系统并直接给你一个root shell。网络通常是关闭的。 这是一个非常安全的修复环境因为根文件系统是只读的避免了误操作。你可以在里面进行fsck、重新安装GRUB、修改密码passwd、修复软件包等操作。操作完成后记得执行mount -o remount, rw /将根文件系统重新挂载为读写模式才能保存更改。关于“适用于 linux 的 windows 子系统必须更新到最新版本”这个WSL2的提示与物理机Linux启动流程无关。它是Windows 10/11内置的Linux子系统在启动时检测到其虚拟化组件版本过旧。解决方法是在Windows中以管理员身份打开PowerShell或CMD执行wsl --update命令来更新WSL内核或者运行提示中给出的wsl.exe --update命令。理解Linux启动流程就像掌握了系统的生命线。从固件自检到服务就绪每一步都环环相扣。无论是为了优化启动速度还是为了在系统崩溃时能冷静地修复这份知识都极其宝贵。下次再遇到启动问题不妨按照这个流程一步步定位你会发现黑屏背后的世界其实清晰可见。
返回列表