1. U-Boot概述:U-Boot的历史、作用与在嵌入式系统中的位置

各位同学,咱们今天聊聊U-Boot。说实话,很多做嵌入式开发的朋友,对U-Boot的态度就是“能用就行”。但真到了板子起不来、内核挂在那不动的时候,才发现自己对这位“看门大爷”几乎一无所知。

我刚开始做嵌入式那会儿,也踩过这个坑。记得有一次调试一块新板子,串口打印停在“Starting kernel ...”就没了下文。我折腾了三天,查内核、查设备树,最后发现是U-Boot传给内核的bootargs里console参数写错了。嗯,从那以后,我再也不敢小看U-Boot了。

1.1 U-Boot从哪里来?

U-Boot的全称是Universal Boot Loader,通用引导加载程序。它的前身是德国DENX软件工程中心的Wolfgang Denx在1999年发起的PPCBoot项目,专门给PowerPC架构用的。

后来ARM架构火了,PPCBoot在2002年改名为U-Boot,开始支持ARM、MIPS、x86等多种架构。到现在,U-Boot已经支持超过30种CPU架构、上千款开发板,是嵌入式领域事实上的标准引导程序。

核心要点:U-Boot不是Linux内核的一部分,它是一个独立的、开源的裸机程序。它的代码仓库在https://source.denx.de/u-boot/u-boot,你也可以从主线拉下来自己裁剪。

1.2 U-Boot到底在干什么?

说白了,U-Boot就干三件事:

  1. 初始化硬件——把CPU、内存、串口、网卡、存储控制器这些基础外设“唤醒”
  2. 加载内核——从Flash、SD卡、网络或USB里把内核镜像读到内存
  3. 传递控制权——设置好启动参数,跳转到内核入口点,把CPU交给Linux

你想想看,如果没有U-Boot,CPU上电后直接跑Linux内核行不行?理论上可以,但实际不行。因为Linux内核假设自己运行在一个已经初始化好的环境中——内存控制器要配好、MMU要关掉、栈指针要设对。这些脏活累活,U-Boot替你干了。

阶段 U-Boot负责 Linux内核负责
上电复位 CPU模式设置、关中断、关MMU —
内存初始化 DDR控制器时序配置、内存测试 接管页表管理
外设驱动 串口、网卡、存储控制器(轻量级) 完整驱动框架
文件系统 支持ext4/FAT/UBIFS(只读加载) 完整VFS
网络协议 TFTP/NFS(用于下载内核) 完整TCP/IP栈

个人经验:我建议你在项目初期就把U-Boot的串口输出完整保存下来。很多启动故障,光看“Starting kernel ...”之前的那几行打印就能定位问题。我曾经靠一个“DRAM: 512 MiB”后面跟的校验警告,发现是DDR时序参数配错了。

1.3 U-Boot在嵌入式系统中的位置

咱们画一张图,把整个启动流程串起来。这样你就能看清U-Boot到底站在哪个位置。

嵌入式系统启动流程 ① 芯片内部 BootROM ② SPL(第一阶段引导) ③ U-Boot 主程序 初始化DDR/串口/网卡 · 加载内核 ④ Linux 内核 解压 · 初始化子系统 · 挂载根文件系统 ⑤ 用户空间(init/应用程序) 关键分界线 U-Boot运行在 裸机环境(无OS) 内核启动后进入OS环境

从这张图你能看到:

  • BootROM是芯片出厂固化的,用户改不了。它负责从指定介质加载SPL。
  • SPL(Secondary Program Loader)是U-Boot的“迷你版”,负责初始化DDR,然后加载完整的U-Boot。
  • U-Boot主程序才是我们平时说的“U-Boot”,它提供命令行、环境变量、网络下载等功能。
  • U-Boot把内核加载到内存后,通过bootm或bootz命令跳转到内核入口,从此U-Boot使命完成。

注意:U-Boot和内核之间通过启动参数(bootargs)和设备树(DTB)通信。如果这两个东西传错了,内核要么起不来,要么起来后找不到串口、网卡。这是调试中最常见的故障点。

1.4 为什么我们要深入学U-Boot?

可能有同学会问:“现在不是有ATF、UEFI、Coreboot这些新东西吗?U-Boot是不是过时了?”

我的回答是:U-Boot依然是嵌入式Linux的事实标准。原因有三:

  1. 硬件覆盖广——从Cortex-M的MCU到Cortex-A72的MPU,从老旧的AT91到最新的i.MX 8,U-Boot都能跑。
  2. 社区活跃——主线U-Boot几乎每周都有更新,新芯片的支持很快就能合入。
  3. 调试手段丰富——U-Boot的命令行本身就是最好的调试工具。你可以手动读内存、写寄存器、测试网卡、烧写Flash。

我个人习惯在项目初期,先把U-Boot的md(内存显示)、mw(内存写)、mm(内存修改)这几个命令玩熟。有一次调试DDR稳定性,我就是用md反复读同一段地址,发现数据偶尔会跳变,才定位到DDR供电纹波过大的硬件问题。

1.5 本章小结

咱们这一章把U-Boot的来龙去脉讲清楚了:

  • 它从PPCBoot发展而来,现在支持几乎所有主流嵌入式CPU
  • 它负责硬件初始化、加载内核、传递控制权
  • 它在启动流程中处于BootROM和Linux内核之间,是承上启下的关键环节
  • 掌握U-Boot调试,是嵌入式Linux开发的基本功