首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >U-Boot 和 Linux 内核的关系及设备树详解

U-Boot 和 Linux 内核的关系及设备树详解

作者头像
一个平凡而乐于分享的小比特
发布2026-02-02 16:35:46
发布2026-02-02 16:35:46
1900
举报

🔥作者简介: 一个平凡而乐于分享的小比特,中南民族大学通信工程专业研究生,研究方向无线联邦学习 🎬擅长领域:驱动开发,嵌入式软件开发,BSP开发 ❄️作者主页:一个平凡而乐于分享的小比特的个人主页 ✨收录专栏:操作系统,本专栏为讲解各操作系统的历史脉络,以及各性能对比,以及内部工作机制,方便开发选择 欢迎大家点赞 👍 收藏 ⭐ 加关注哦!💖💖

在这里插入图片描述
在这里插入图片描述

U-Boot 和 Linux 内核的关系及设备树详解

一、U-Boot 和 Linux 内核的关系

系统启动流程全景图
代码语言:javascript
复制
┌─────────────────────────────────────────────────────┐
│                 嵌入式系统启动流程                   │
├─────────────────────────────────────────────────────┤
│ 阶段 1:硬件复位 → BootROM(固化在芯片中)           │
│          ↓                                          │
│ 阶段 2:U-Boot(第一阶段:SPL)                      │
│          ↓                                          │
│ 阶段 3:U-Boot(第二阶段:主程序)                   │
│          ↓                                          │
│ 阶段 4:Linux 内核(内核初始化)                    │
│          ↓                                          │
│ 阶段 5:根文件系统 → 用户空间                       │
└─────────────────────────────────────────────────────┘
U-Boot 的作用(系统引导程序)

U-Boot(Universal Bootloader) 相当于嵌入式系统的"启动管家",主要负责:

主要功能:
  1. 硬件初始化 - CPU、内存、时钟、串口等
  2. 加载内核 - 从存储设备(eMMC、SD卡、Flash)读取内核镜像
  3. 传递参数 - 通过设备树和命令行参数告诉内核硬件信息
  4. 引导启动 - 跳转到内核入口点,移交控制权
类比理解:建筑工地开工
代码语言:javascript
复制
┌─────────┐     ┌─────────┐     ┌─────────┐
│  毛坯房  │━━━━▶│ 施工队   │━━━━▶│ 精装房  │
│ (硬件)   │     │ (U-Boot) │     │ (Linux) │
└─────────┘     └─────────┘     └─────────┘
     │               │               │
 只有水泥墙      通水通电、         装修完成
  和地基        搬运建材           可入住
启动过程详细时序
代码语言:javascript
复制
// 简化版的启动过程代码示意
void boot_process(void) {
    // 1. 硬件复位(不可控,芯片自动执行)
    
    // 2. U-Boot第一阶段(SPL)
    chip_hardware_init();      // 初始化最基础硬件
    load_uboot_image();        // 加载U-Boot主程序
    jump_to_uboot();           // 跳转到U-Boot
    
    // 3. U-Boot第二阶段
    init_all_hardware();       // 初始化所有外设
    load_device_tree();        // 加载设备树
    load_kernel_image();       // 加载Linux内核
    set_boot_args();           // 设置启动参数
    jump_to_kernel(0x80008000);// 跳转到内核
    
    // 4. Linux内核接管
    // U-Boot的使命结束,生命周期终止
}

二、设备树(Device Tree)全面解析

什么是设备树?

设备树是一种描述硬件配置的数据结构,相当于硬件的"身份证"和"说明书"。

设备树的演进历史
代码语言:javascript
复制
2005年前:代码硬编码          → 2010年后:设备树标准
├─ ARM平台:板级文件           ├─ 一个.dts文件描述硬件
├─ 大量arch/arm/mach-*目录     ├─ 内核通用,无需修改
├─ 内核臃肿,移植困难          ├─ 内核精简,易于移植
└─ 每个板子需要内核修改        └─ 只需替换设备树文件
设备树文件类型
代码语言:javascript
复制
├── 源文件(人类可读可编辑)
│   ├── dts(Device Tree Source)      - 具体板子的设备树
│   └── dtsi(Device Tree Source Include)- 公共部分,可被包含
│
├── 中间文件(编译过程生成)
│   └── dtb(Device Tree Blob)        - 二进制格式,由dts编译
│
└── 运行时(内存中)
    └── FDT(Flattened Device Tree)   - dtb加载到内存后的结构

三、U-Boot设备树 vs Linux内核设备树

详细对比表格

特性

U-Boot 设备树

Linux 内核 设备树

说明

主要目的

硬件初始化和配置

内核驱动识别硬件

U-Boot用来"点亮"硬件,内核用来"驱动"硬件

生命周期

启动阶段使用

整个系统运行期使用

U-Boot完成任务后销毁,内核持续使用

修改权限

可修改、可调整

只读参考

U-Boot可动态修改DTB再传给内核

包含内容

基础硬件描述+U-Boot专用节点

完整硬件描述+内核驱动绑定

典型差异

可能包含内存测试节点、引导参数

包含中断控制器、时钟、DMA等复杂外设

文件位置

U-Boot源码:arch/*/dts/*.dts

Linux源码:arch/*/boot/dts/*.dts

通常同名但内容有差异

场景示例:SD卡控制器配置
代码语言:javascript
复制
// U-Boot 的 SD 卡设备树片段 (简化)
sdhci: sdhci@fe330000 {
    compatible = "snps,dwcmshc-sdhci";
    reg = <0x0 0xfe330000 0x0 0x10000>;
    clocks = <&cru SCLK_SDMMC>;
    clock-names = "core";
    u-boot,dm-spl;                    // ← U-Boot专用属性
    status = "okay";
};

// Linux 内核的 SD 卡设备树片段
sdhci: sdhci@fe330000 {
    compatible = "snps,dwcmshc-sdhci";
    reg = <0x0 0xfe330000 0x0 0x10000>;
    interrupts = <GIC_SPI 12 IRQ_TYPE_LEVEL_HIGH>; // ← 内核需要中断
    clocks = <&cru SCLK_SDMMC>, <&cru TMCLK_SDMMC>;
    clock-names = "core", "timeout";
    resets = <&cru SRST_SDMMC>;       // ← 内核需要复位控制
    reset-names = "reset";
    status = "okay";
};

四、设备树的传递流程

完整传递过程图示
代码语言:javascript
复制
┌─────────────────────────────────────────────────────────────┐
│               设备树从源码到内核的完整流程                    │
├─────────────┬─────────────┬─────────────┬─────────────┤
│    阶段1    │    阶段2    │    阶段3    │    阶段4    │
│  源码准备   │  编译阶段   │   U-Boot    │  内核使用   │
├─────────────┼─────────────┼─────────────┼─────────────┤
│ 开发板.dts  │  dtc编译器  │  加载DTB    │  解析DTB    │
│   +         │     ↓       │    到内存   │     ↓       │
│  SoC.dtsi   │  board.dtb  │     ↓       │ 创建platform│
│   +         │  (二进制)   │ 可选:修改  │  设备       │
│ common.dtsi │             │  设备树     │     ↓       │
│             │             │     ↓       │ 匹配驱动    │
│             │             │ 传递给内核  │     ↓       │
│             │             │             │ 初始化硬件  │
└─────────────┴─────────────┴─────────────┴─────────────┘
实际启动示例:Raspberry Pi 4
代码语言:javascript
复制
# 编译过程
$ make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- dtbs
# 生成: bcm2711-rpi-4-b.dtb

# U-Boot 加载流程
U-Boot> load mmc 0:1 ${kernel_addr_r} Image
U-Boot> load mmc 0:1 ${fdt_addr_r} bcm2711-rpi-4-b.dtb
U-Boot> fdt addr ${fdt_addr_r}          # 设置设备树地址
U-Boot> fdt resize 8192                 # 调整大小(可选)
U-Boot> fdt set /chosen bootargs "console=ttyAMA0"  # 修改参数
U-Boot> booti ${kernel_addr_r} - ${fdt_addr_r}

# Linux内核启动日志片段(可以看到设备树解析)
[    0.000000] OF: fdt: Machine model: Raspberry Pi 4 Model B
[    0.000000] printk: console [ttyAMA0] enabled
[    0.123456] mmc0: SDHCI controller on fe340000.mmc [fe340000.mmc]

五、常见问题和调试技巧

1. 设备树不匹配的症状
代码语言:javascript
复制
症状                         可能原因
──────────────────────────────────────────────────────
内核panic,找不到根文件系统      内存地址配置错误
某个外设不工作                  设备树节点缺失或配置错误
内核无法启动,卡在early boot    设备树格式错误或版本不兼容
2. 调试命令和工具
U-Boot 中的设备树操作:
代码语言:javascript
复制
# 查看设备树
U-Boot> fdt print /soc/mmc@fe330000

# 修改设备树(临时)
U-Boot> fdt set /soc/mmc@fe330000 status "disabled"

# 保存修改后的设备树
U-Boot> fdt save ${fdt_addr_r}

# 检查设备树完整性
U-Boot> fdt checks
Linux 内核中的设备树查看:
代码语言:javascript
复制
# 查看系统中的设备树
$ ls /proc/device-tree/

# 查看特定设备属性
$ cat /proc/device-tree/soc/mmc@fe330000/compatible

# 使用dtc工具反编译DTB
$ dtc -I dtb -O dts -o output.dts /boot/bcm2711-rpi-4-b.dtb
3. 设备树覆盖(Device Tree Overlay)

适用于动态修改硬件配置:

代码语言:javascript
复制
原设备树DTB + 叠加overlay.dtbo = 新配置
     ↓              ↓
 基础硬件配置    特定扩展板配置

六、最佳实践和开发建议

设备树编写原则:
  1. 复用原则:相同SoC使用同一个.dtsi,具体板子.dts包含它
  2. 最小差异:板级设备树只描述与参考设计不同的部分
  3. 属性规范:严格按照bindings文档编写属性
  4. 版本控制:设备树与内核版本、U-Boot版本匹配
工作流程图解:

总结:核心要点回顾

  1. U-Boot是引导程序,内核是操作系统,两者接力完成启动
  2. 设备树是硬件描述文件,避免内核代码硬编码硬件信息
  3. U-Boot和内核各有设备树,前者用于初始化,后者用于驱动
  4. 设备树可以传递和修改,U-Boot可调整后再传给内核
  5. 设备树使内核通用化,同一内核支持不同硬件只需换设备树
一句话概括:

U-Boot用设备树初始化硬件,然后把"硬件说明书"(设备树)交给Linux内核,内核根据说明书加载驱动、管理硬件。

这种设计实现了硬件描述与内核代码的分离,大大提高了嵌入式系统的可移植性和可维护性,是现代嵌入式Linux系统的标准架构。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2026-01-03,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • U-Boot 和 Linux 内核的关系及设备树详解
    • 一、U-Boot 和 Linux 内核的关系
      • 系统启动流程全景图
      • U-Boot 的作用(系统引导程序)
      • 类比理解:建筑工地开工
      • 启动过程详细时序
    • 二、设备树(Device Tree)全面解析
      • 什么是设备树?
      • 设备树的演进历史
      • 设备树文件类型
    • 三、U-Boot设备树 vs Linux内核设备树
      • 详细对比表格
      • 场景示例:SD卡控制器配置
    • 四、设备树的传递流程
      • 完整传递过程图示
      • 实际启动示例:Raspberry Pi 4
    • 五、常见问题和调试技巧
      • 1. 设备树不匹配的症状
      • 2. 调试命令和工具
      • 3. 设备树覆盖(Device Tree Overlay)
    • 六、最佳实践和开发建议
      • 设备树编写原则:
      • 工作流程图解:
    • 总结:核心要点回顾
      • 一句话概括:
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档