本文约2600字,今天继续沿着《一份靠谱的BSP开发学习路线》来学习BSP开发所需的知识--Linux内核启动流程。本文根据爱芯AX615 armv7系列4.19.125版本的内核源码来梳理内核启动流程。
关注公众号, 即可获得与Linux相关的电子书籍以及常用开发工具,文末有文档清单。
一 启动总览(AX615 架构)
AX615 为 armv7架构,内核启动遵循BootROM->U-Boot->内核自解压->汇编初始化->C 语言核心初始化->用户态切换的标准流程,各阶段严格衔接,完成从硬件到系统的完整初始化。
核心流程如下:
硬件上电 -> BootROM(片上 ROM)-> 加载 U-Boot
U-Boot -> 加载内核镜像(zImage/Image)+ DTB → 跳转内核入口
内核自解压(压缩镜像)-> 执行汇编入口stext
汇编初始化 -> 建立页表 / MMU -> 跳转start_kernel(C 入口)
start_kernel -> 子系统初始化 -> rest_init -> 内核线程kernel_init
挂载根文件系统 -> 启动用户态init进程 -> 系统就绪
二 阶段 1:BootROM 与 U-Boot 引导(内核启动前序)
[1]. BootROM 阶段(AX615 片上 ROM,不可修改)
功能:上电复位后 CPU 从固定地址执行,初始化时钟、DDR 控制器、存储接口(eMMC/SD/SPI-NOR),从指定介质加载 U-Boot 到 DDR
关键路径:AX615 专用 BootROM 代码(厂商提供,非内核源码)
参数传递:加载 U-Boot 后,将启动介质、DDR 配置等信息传递给 U-Boot
[2]. U-Boot 阶段(AX615 定制 U-Boot,内核启动 “桥梁”)
核心任务:
>>完整初始化 DDR(AX615 专用 DDR 驱动),建立内存运行环境
>>从存储介质读取 内核镜像(zImage/Image)与设备树(DTB,xxx.dtb)到 DDR 指定地址
>>解析启动参数(bootargs),设置寄存器:r0=0、r1=机器ID、r2=DTB物理地址
>>执行bootm命令,跳转至内核镜像入口,将控制权完全交给内核
三 阶段 2:内核自解压(压缩镜像必备)
[1]. 入口与核心文件
入口地址:U-Boot 跳转的内核镜像起始地址(物理地址,MMU 关闭)
核心文件路径(内核源码):arch/arm/boot/compressed/head.S
链接脚本:arch/arm/boot/compressed/vmlinux.lds.S(定义解压代码布局)
[2]. 自解压流程(head.S执行)
>>保存 U-Boot 传递的寄存器参数(r0/r1/r2)
>>初始化解压栈,关闭中断,配置 CPU 缓存(D-cache/I-cache)
>>调用decompress_kernel()(arch/arm/boot/compressed/misc.c),解压内核镜像到 DDR 高端地址
>>解压完成后打印:Uncompressing Linux... done, booting the kernel.
>>清理解压环境,跳转至内核真正入口stext(虚拟地址0xffff000008000000,armv7标准)
四 阶段 3:汇编初始化(stext,内核第一行执行代码)
[1]. 核心文件与入口
入口符号:stext(内核链接脚本ENTRY(stext)指定)
文件路径:arch/arm/kernel/head.S(armv7架构核心汇编文件)
链接脚本:arch/arm/kernel/vmlinux.lds.S(编译生成vmlinux.lds,定义内核内存布局)
[2]. 汇编初始化关键步骤(head.S)
>>CPU 与架构校验
检查 CPU ID 是否匹配 AX615,不匹配则启动失败
验证机器类型与 DTB 兼容性,确保硬件与内核配置一致
>>内存与 MMU 初始化(最核心)
建立内核页表(swapper_pg_dir,arch/arm/mm/proc.S),完成物理地址→虚拟地址映射
使能 MMU 与缓存(D-cache/I-cache),切换到虚拟地址空间,为 C 代码运行奠基
初始化内核栈(init_thread_union),设置栈指针sp
>>BSS 段清零与参数处理
清零.bss段(未初始化全局变量),避免随机值干扰
解析 U-Boot 传递的 DTB 地址(r2),保存至全局变量__fdt_pointer
关闭所有中断,设置异常向量表(vectors,arch/arm/kernel/entry.S)
>>跳转 C 语言入口
执行bl start_kernel,从汇编世界进入 C 语言世界,内核核心初始化开始
五 阶段 4:C 语言核心初始化(start_kernel,内核 “总控中心”)
[1]. 核心文件与入口
函数定义:init/main.c(内核通用 C 入口,所有架构共享)
函数原型:asmlinkage __visible void __init start_kernel(void)
[2]. start_kernel关键初始化流程(按执行顺序)
>>基础环境初始化
sched_clock_init():初始化调度时钟,为时间管理奠基
setup_arch(&command_line):AX615 架构核心初始化(arch/arm/kernel/setup.c)
解析 DTB,获取 硬件信息(内存、中断、时钟、外设)
初始化内存管理(memblock),标记可用 / 保留内存区域
注册平台设备与驱动
parse_early_param():解析内核启动参数(bootargs)
setup_log_buf():初始化日志缓冲区,启动内核打印
>>子系统初始化(核心模块依次启动)

>>后续初始化与线程启动
vfs_caches_init():虚拟文件系统缓存初始化
buffer_init()/pagecache_init():页缓存、缓冲区初始化
fork_init():进程管理初始化(最大 PID、进程表)
rest_init():启动内核线程,进入用户态准备(init/main.c)
六 阶段 5:rest_init与用户态切换(内核->用户空间)
[1]. rest_init核心逻辑(init/main.c)
创建内核线程 1(PID=1):执行kernel_init函数(内核第一个线程)
创建kthreadd 线程(PID=2):管理所有内核线程,负责内核线程创建 / 销毁
0 号进程(init_task)进入cpu_idle()循环,成为空闲进程(系统无任务时执行)
[2]. kernel_init流程(init/main.c,PID=1)
>>内核线程初始化
kernel_init_freeable():完成剩余内核初始化(驱动、网络、文件系统)
do_basic_setup():
driver_init():设备驱动模型初始化(总线、设备、驱动注册)
initcalls:执行所有__init标记的初始化函数(AX615 外设驱动:I2C、SPI、GPIO、以太网等)
>>挂载根文件系统(关键)
prepare_namespace():解析root=参数,挂载根文件系统
mount_root():实际挂载根分区,完成从临时文件系统到真实根文件系统的切换
>>启动用户态init进程
init_post():
关闭内核控制台,释放启动资源
执行run_init_process(),尝试启动用户态init程序
(顺序: /sbin/init->/etc/init->/bin/init->/bin/sh)
若成功,内核态 PID=1 消失,用户态init进程(PID=1)接管系统,进入用户空间
七 专用关键文件汇总
架构通用核心文件:
内核入口汇编:arch/arm/kernel/head.S
自解压入口:arch/arm/boot/compressed/head.S
C 语言总入口:init/main.c(start_kernel/rest_init/kernel_init)
架构初始化:arch/arm/kernel/setup.c
内存管理:arch/arm/mm/mmu.c、mm/mm_init.c
中断处理:arch/arm/kernel/irq.c、kernel/irq/irqdesc.c
八 启动流程关键节点总结
[1].BootROM:硬件上电->初始化基础外设->加载 U-Boot
[2].U-Boot:DDR 初始化->加载内核 + DTB->跳转内核入口
[3].自解压:arch/arm/boot/compressed/head.S->解压内核->跳转stext
[4].汇编初始化:arch/arm/kernel/head.S->MMU/页表/栈初始化->bl start_kernel
[5].C 核心初始化:init/main.c->start_kernel->子系统初始化->rest_init
[6].用户态切换:kernel_init->挂载根文件系统->启动/sbin/init->系统就绪
九 调试与排查建议
[1].启动卡死在解压阶段:检查 U-Boot 加载内核地址、DDR 初始化是否正常、内核镜像是否损坏
[2].卡死在 stext汇编阶段:核对 DTB 与内核兼容性、MMU 页表配置、AX615 CPU ID 校验
[3].卡死在start_kernel后:开启内核调试打印(bootargs添加debug),定位子系统初始化失败点
[4].根文件系统挂载失败:检查root=参数、存储驱动(eMMC/SD)是否初始化、文件系统格式是否正确
以上为全文内容。

这里是女程序员的笔记本
15年+嵌入式软件工程师兼二胎宝妈
分享读书心得、工作经验,自我成长和生活方式。
希望我的文字能对你有所帮助