U-Boot(Universal Bootloader)作为嵌入式系统中广泛使用的引导程序,其加载内核和文件系统的过程涉及多个阶段和复杂的交互逻辑。以下是更详细的工作流程解析:

一、U-Boot 自身启动流程(为加载内核做准备)

  1. 硬件初始化阶段(第一阶段)

    • 固化代码执行:系统上电后,CPU 从固化的 ROM(如片内 Boot ROM)开始执行,完成最基础的硬件初始化(如关闭看门狗、设置 CPU 时钟、初始化 SRAM)。
    • 加载 SPL(Secondary Program Loader):若系统内存为 DDR(需要复杂初始化),ROM 代码会将 SPL(小型引导程序)从存储设备(如 NAND Flash、SD 卡)加载到 SRAM 中执行。
    • DDR 初始化:SPL 负责完成 DDR 内存的完整初始化(时序配置、刷新参数等),为加载 U-Boot 主程序准备内存空间。
  2. U-Boot 主程序加载(第二阶段)

    • SPL 将 U-Boot 主程序从存储设备(如 Flash)读取到 DDR 内存中,并跳转到主程序入口。
    • 主程序初始化更多硬件(如网络、USB、显示设备),检测存储设备,并设置环境变量(从 Flash 的环境变量分区读取或使用默认值)。

二、加载内核(Kernel)的详细步骤

  1. 确定内核和设备树的存储位置

    • U-Boot 通过环境变量定位内核和设备树(DTB)的存储路径,例如:
      • kernel_offset:内核在存储设备中的偏移地址(如 Flash 的 0x200000 处)。
      • fdt_offset:设备树在存储设备中的偏移地址(如 0x100000 处)。
      • loadaddr:内核在内存中的加载地址(如 0x80800000,需避开 U-Boot 自身占用的内存区域)。
  2. 读取内核镜像到内存

    • 根据存储设备类型,U-Boot 调用对应的驱动程序读取内核:
      • MMC/SD 卡mmc read ${loadaddr} ${kernel_offset} ${kernel_size}(从 MMC 设备读取指定块到内存)。
      • NAND Flashnand read ${loadaddr} ${kernel_offset} ${kernel_size}
      • 网络加载tftpboot ${loadaddr} 192.168.1.100:zImage(通过 TFTP 从服务器下载)。
    • 内核镜像类型:常见的有zImage(压缩内核,自带解压功能)、uImage(U-Boot 专用格式,包含头部信息和校验和)。
  3. 读取设备树(DTB)到内存

    • 设备树是描述硬件信息的二进制文件(.dtb),U-Boot 将其加载到另一段内存(如fdtaddr=0x81000000):
      • mmc read ${fdtaddr} ${fdt_offset} ${fdt_size}
    • 可选操作:U-Boot 可动态修改 DTB 内容(如通过fdt set命令修改节点属性),适配硬件动态配置。

三、启动内核:传递参数并移交控制权

  1. 构造内核启动参数(bootargs)

    • U-Boot 通过bootargs环境变量向内核传递参数,例如:

      bash

      bootargs=console=ttyS0,115200 root=/dev/mmcblk0p2 rw rootfstype=ext4 init=/sbin/init
      
       
      • console:指定内核输出控制台(如串口 ttyS0,波特率 115200)。
      • root:指定根文件系统的存储位置(如 MMC 分区 2)。
      • rootfstype:指定文件系统类型(如 ext4)。
      • rw:以读写模式挂载根文件系统。
  2. 启动内核指令

    • 根据内核类型,U-Boot 使用不同命令启动:
      • 启动zImage+DTBbootz ${loadaddr} - ${fdtaddr}-表示无 initramfs)。
      • 启动uImagebootm ${loadaddr}(uImage 头部包含内核信息,无需单独指定 DTB 地址)。
    • 底层实现:U-Boot 通过汇编指令(如 ARM 的blbx)跳转到内核在内存中的入口地址,同时将bootargs和 DTB 的地址存入指定寄存器(如 ARM 的 r0、r1、r2),供内核读取。

四、文件系统的加载与挂载(内核主导)

U-Boot 不直接加载文件系统,而是由内核完成挂载,过程如下:

  1. 内核初始化阶段

    • 内核启动后,先执行自身初始化(如内存管理、进程调度、驱动框架初始化),并解析 U-Boot 传递的bootargs参数。
  2. 定位并挂载根文件系统

    • 内核根据root参数找到文件系统存储位置(如/dev/mmcblk0p2对应 SD 卡第 2 分区)。
    • 加载对应文件系统的驱动(如 ext4、ubifs 驱动),检测存储设备上的文件系统结构。
    • 执行挂载操作:将根文件系统挂载到/目录,此时内核可访问/bin/sbin/etc等目录。
  3. 启动用户空间进程

    • 内核挂载文件系统后,启动第一个用户进程(/sbin/init/bin/systemd),由其负责初始化用户空间服务(如网络、登录终端),最终完成系统启动。

五、关键机制与配置

  1. 环境变量的作用

    • U-Boot 的环境变量存储在 Flash 的专用分区,可通过printenv查看、setenv修改,例如:
      • bootcmd:自动执行的启动命令(如mmc read ...; bootz ...),决定了 U-Boot 如何加载内核。
      • bootdelay:启动倒计时(秒),期间可按按键进入 U-Boot 命令行,手动干预启动流程。
  2. 故障处理机制

    • 若内核加载失败(如校验和错误、地址错误),U-Boot 会停留在命令行,允许用户手动输入命令重试。
    • 部分系统支持多内核备份:bootcmd中可配置检测主内核是否有效,无效则加载备份内核。
  3. initramfs 的特殊情况

    • 若系统使用initramfs(内存文件系统),U-Boot 需将其与内核、DTB 一起加载到内存,内核先挂载initramfs,再由其完成根文件系统的挂载(适用于复杂启动场景)。

总结

U-Boot 的核心职责是搭建硬件环境→加载内核和设备树→传递启动参数→移交控制权,而文件系统的挂载则由内核根据 U-Boot 提供的参数完成。整个流程依赖于存储设备驱动、内存管理和硬件适配,不同嵌入式平台(如 ARM、PowerPC)的细节可能略有差异,但核心逻辑一致。

Logo

魔乐社区(Modelers.cn) 是一个中立、公益的人工智能社区,提供人工智能工具、模型、数据的托管、展示与应用协同服务,为人工智能开发及爱好者搭建开放的学习交流平台。社区通过理事会方式运作,由全产业链共同建设、共同运营、共同享有,推动国产AI生态繁荣发展。

更多推荐