
本文概述
Linux系统启动流程是嵌入式Linux面试的基础必考题,考察对整个启动链路的理解深度。完整启动分为四个阶段:Bootloader阶段完成硬件初始化并加载内核;内核阶段完成内核自身初始化和根文件系统挂载;init阶段启动第一个用户态进程;用户空间阶段完成系统服务和应用程序启动。U-Boot是嵌入式最常用的Bootloader,通过bootargs向内核传递启动参数。理解每个阶段的作用和关键节点,才能快速定位启动失败等问题。
Linux系统启动流程是怎样的?嵌入式Linux面试Bootloader到用户空间全过程
核心要点速览
启动分四大阶段:Bootloader → 内核 → init → 用户空间
U-Boot是嵌入式最常用的Bootloader
bootargs是Bootloader传给内核的启动参数
内核最后一步是挂载根文件系统并启动init进程
init是第一个用户空间进程,PID永远是1
面试题
请详细描述嵌入式Linux系统从上电到进入命令行的完整启动流程,每个阶段做了什么事情?如果系统启动卡在挂载根文件系统,你会怎么排查?
面试官考察点
是否清楚Linux启动的完整链路
对Bootloader、内核、文件系统各自职责的理解
U-Boot的实际使用经验
启动参数bootargs的配置
启动故障的排查能力
回答思路
Linux的启动过程是一个层层递进的链路,每个阶段负责不同的事情,可以按时间顺序来梳理:
第一阶段:上电复位与Bootloader启动
上电后CPU从复位地址开始执行第一条指令,这个地址通常映射到Flash或ROM。芯片内部的固化程序(如ROM Code)首先运行,做最基本的硬件初始化,然后从Flash、SD卡或USB等介质加载Bootloader到内存。
嵌入式系统最常用的Bootloader是U-Boot。U-Boot做的事情包括:
初始化串口、SDRAM、Flash、网卡等基本硬件
提供命令行交互界面,支持调试和参数配置
加载内核镜像(zImage或uImage)和设备树(dtb)到内存
设置bootargs启动参数并传递给内核
调用bootm或bootz命令启动内核
U-Boot的环境变量中,bootcmd是自动启动时执行的命令,bootargs是传给内核的参数,这两个是最关键的。
第二阶段:内核启动
U-Boot跳转到内核入口后,内核开始启动,主要过程是:
架构初始化:设置CPU、MMU、页表、中断向量表等架构相关的底层初始化
内核自解压:如果是压缩内核(zImage),先自解压到内存
设备树解析:解析传入的设备树blob,识别硬件平台信息
子系统初始化:依次初始化内存管理、进程管理、文件系统、网络、驱动等各个子系统
驱动初始化:按编译顺序初始化各个设备驱动,探测并注册设备
挂载根文件系统:根据bootargs中的root参数找到根设备,挂载根文件系统
启动init进程:在内核最后阶段,启动第一个用户空间进程init,PID为1
内核启动阶段如果打开了earlyprintk,就能在串口看到内核的打印信息,包括各个子系统初始化的日志和驱动加载信息。
第三阶段:init进程与系统初始化
init进程是用户空间的第一个进程,PID永远是1,它负责启动和管理所有其他用户进程。Linux系统中init有几种实现方式:
SysVinit:传统的System V init,用运行级别和rc脚本来管理服务
systemd:现代Linux系统主流init系统,并行启动、依赖管理、单元文件配置
BusyBox init:嵌入式常用的轻量级init,用inittab配置,简单省资源
嵌入式系统因为资源有限,很多用BusyBox自带的init。init进程启动后会读取配置文件,然后依次执行初始化脚本,挂载其他文件系统,启动系统服务和守护进程。
第四阶段:用户空间与应用启动
最后是用户空间的完整初始化:
启动各种系统服务(网络、日志、定时任务等)
配置网络接口、设置主机名、加载模块
启动登录程序(getty或sshd)
如果是图形界面,启动显示管理器和桌面环境
嵌入式产品通常直接启动自己的应用程序
到用户能登录或应用程序正常运行,整个启动流程就完成了。
第五、根文件系统挂载失败的排查思路
面试中的第二个问题是根文件系统挂不上怎么排查,这是实际工作中经常遇到的问题:
第一步:确认bootargs配置
先看bootargs里的root参数是否正确,比如root=/dev/mmcblk0p2有没有写错设备名,rootfstype指定的文件系统类型对不对。
第二步:看内核是否识别到存储设备
打开earlyprintk看内核启动日志,找mmc、sd、mtd相关的打印,确认内核是否正确识别出了SD卡、eMMC或Flash设备,以及分区是否正确。如果设备都没识别到,说明是驱动问题。
第三步:检查内核驱动配置
存储设备驱动和文件系统必须编译进内核(built-in),不能编译成模块,因为模块本身就在根文件系统里,没挂载之前加载不了。确认内核配置里有没有打开对应的控制器驱动和文件系统(如ext4、yaffs2、ubifs等)。
第四步:检查根文件系统内容
用U-Boot的命令(如mmc read、nand read)读出存储设备内容,或者把存储设备接到电脑上看,确认根文件系统镜像是否正确烧写进去了,分区是否正常,init程序是否存在。
第五步:检查init程序
内核挂载rootfs后会尝试执行init(默认/sbin/init),如果init文件不存在、没有执行权限、或者依赖的库缺失,也会启动失败。可以在bootargs里加init=/bin/sh来直接进shell调试。
常见追问
失分表达
"上电后直接运行Linux内核"——不知道Bootloader的存在
"init就是systemd"——把特定实现和概念混淆
"根文件系统挂载不上就是文件系统坏了"——排查思路单一
"bootargs是内核自己读的"——不理解参数传递机制
准备动作
亲手移植或搭建过一个嵌入式Linux系统,从U-Boot到内核到rootfs都做过
熟悉U-Boot的常用命令和环境变量配置
了解内核启动过程的主要阶段和关键函数
有实际调试启动问题的经验
理解设备树的基本概念和使用方法
核心关键词
Linux启动流程 U-Boot Bootloader 内核启动 根文件系统 init进程 bootargs 嵌入式Linux面试

扫码关注




























