Linux基础 -- SoC从uboot到linux kernel的全过程

发布于:2025-03-25 ⋅ 阅读:(27) ⋅ 点赞:(0)

总体流程概览(ARM 平台,Device Tree 支持)

[上电 / 复位]
     ↓
[Boot ROM (SoC 内部)]
     ↓
[1st Stage Bootloader (如 SPL)]
     ↓
[2nd Stage Bootloader: U-Boot]
     ↓
[Load Linux Kernel、DTB、Initramfs]
     ↓
[设置内核启动参数/设备树/内存布局]
     ↓
[跳转到内核入口 __start(),Kernel 开始执行]

一、上电后的 BootROM 阶段(由 SoC 厂商固化)

  • 通常由 ARM SoC 厂商提供,不可修改;
  • 功能:初始化 Boot 设备(SPI-NAND、eMMC、SD、USB等);
  • 加载 SPL(二级引导前的小型启动代码)到 SRAM,跳转执行。

二、SPL(Secondary Program Loader)阶段

功能:

  • 初始化 DRAM;
  • 加载完整的 U-Boot 镜像到内存;
  • 跳转到 U-Boot。

注意:若 SoC 有 SRAM 限制严重,必须使用 SPL 机制;否则直接进入 U-Boot。


三、U-Boot 主程序阶段(bootloader)

这是 加载并启动 Linux 的关键阶段


1. 加载内核镜像、设备树、initramfs(可选)

  • 一般从 eMMC/NAND/SD 卡/FAT/ext4 文件系统中读取:
ext4load mmc 0:1 0x80000 Image         # 加载内核
ext4load mmc 0:1 0x40000 dtb           # 加载设备树
ext4load mmc 0:1 0x2000000 initrd.img  # 可选加载 initramfs

U-Boot 通常使用如下内存地址布局(不同平台略有不同):

模块 地址(示例)
kernel 0x800000x80080000
dtb 0x400000x83000000
initrd 0x2000000

2. 设置 bootargs / ATAG / FDT 参数

  • 设置传给内核的启动参数(cmdline):
setenv bootargs "console=ttyAMA0 root=/dev/mmcblk0p2 rootwait"
  • ARMv7: 使用 ATAG 参数结构体(较老)
  • ARMv8: 使用设备树(FDT)

U-Boot 通过环境变量 bootargs 构造 cmdline


3. 调用 bootm / booti 命令启动内核

  • bootm:用于启动传统的 uImage(带 U-Boot header)
  • booti:用于启动裸内核 Image(AArch64)
  • bootz:启动 zImage(压缩内核)

示例命令:

booti 0x80000 - 0x40000
#         │     │     └── 设备树地址
#         │     └── initrd(若无填 -)
#         └── kernel image 加载地址

四、U-Boot 跳转到 Linux 内核入口

在调用 booti/bootm 时,U-Boot 做了以下事情:

设置 CPU 运行状态

  • ARMv7:设置为 SVC 模式(关闭中断);
  • ARMv8:设置 EL2 → EL1,以 EL1 执行内核;
  • 关闭 MMU、Cache,或根据配置保留 L2;

设置寄存器

  • ARMv7:

    • R0 = 0(机器 ID)
    • R1 = 机器 ID(老方式)
    • R2 = ATAG 地址或 DTB 地址
  • ARMv8:

    • x0 = FDT blob 地址(必须)
    • x1~x3 = 0

最后使用汇编跳转:

# ARMv7:
mov     r0, #0
ldr     r1, =machine_id
ldr     r2, =atags_addr  ; 或 dtb
mov     pc, r0           ; 跳转到内核入口

# ARMv8:
mov     x0, dtb_addr
br      x1               ; x1 指向 kernel __start

五、Linux 内核执行入口 (__start)

内核镜像的起始点通常是:

// ARMv8-A arch/arm64/kernel/head.S
ENTRY(__start)
    // 关闭 MMU/Cache(如果 U-Boot 没做)
    // 设置页表、栈、EL级别
    // 跳转到 start_kernel()

总结:U-Boot 启动 Linux 的关键点

阶段 关键任务
SPL 初始化 RAM,加载 U-Boot
U-Boot 初始化设备、加载 kernel/dtb/initrd
设置参数 设定 bootargs,填充 FDT
跳转 设置寄存器、进入内核入口
内核启动 进入 start_kernel(),开始内核世界

推荐配置文件(U-Boot)

在移植或开发过程中,关注:

  • include/configs/xxx.h:配置内存映射、启动参数;
  • board/xxx/xxx.c:板级初始化;
  • cmd/booti.c / cmd/bootm.c:启动命令实现;
  • arch/arm/lib/bootm.c:真正的跳转代码。

网站公告

今日签到

点亮在社区的每一天
去签到