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

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

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

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

系统启动流程全景图

┌─────────────────────────────────────────────────────┐ │ 嵌入式系统启动流程 │ ├─────────────────────────────────────────────────────┤ │ 阶段 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. 引导启动 - 跳转到内核入口点,移交控制权

类比理解:建筑工地开工

┌─────────┐ ┌─────────┐ ┌─────────┐ │ 毛坯房 │━━━━▶│ 施工队 │━━━━▶│ 精装房 │ │ (硬件) │ │ (U-Boot) │ │ (Linux) │ └─────────┘ └─────────┘ └─────────┘ │ │ │ 只有水泥墙 通水通电、 装修完成 和地基 搬运建材 可入住 

启动过程详细时序

// 简化版的启动过程代码示意voidboot_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)全面解析

什么是设备树?

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

设备树的演进历史

2005年前:代码硬编码 → 2010年后:设备树标准 ├─ ARM平台:板级文件 ├─ 一个.dts文件描述硬件 ├─ 大量arch/arm/mach-*目录 ├─ 内核通用,无需修改 ├─ 内核臃肿,移植困难 ├─ 内核精简,易于移植 └─ 每个板子需要内核修改 └─ 只需替换设备树文件 

设备树文件类型

├── 源文件(人类可读可编辑) │ ├── 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/*.dtsLinux源码:arch/*/boot/dts/*.dts通常同名但内容有差异

场景示例:SD卡控制器配置

// 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"; }; 

四、设备树的传递流程

完整传递过程图示

┌─────────────────────────────────────────────────────────────┐ │ 设备树从源码到内核的完整流程 │ ├─────────────┬─────────────┬─────────────┬─────────────┤ │ 阶段1 │ 阶段2 │ 阶段3 │ 阶段4 │ │ 源码准备 │ 编译阶段 │ U-Boot │ 内核使用 │ ├─────────────┼─────────────┼─────────────┼─────────────┤ │ 开发板.dts │ dtc编译器 │ 加载DTB │ 解析DTB │ │ + │ ↓ │ 到内存 │ ↓ │ │ SoC.dtsi │ board.dtb │ ↓ │ 创建platform│ │ + │ (二进制) │ 可选:修改 │ 设备 │ │ common.dtsi │ │ 设备树 │ ↓ │ │ │ │ ↓ │ 匹配驱动 │ │ │ │ 传递给内核 │ ↓ │ │ │ │ │ 初始化硬件 │ └─────────────┴─────────────┴─────────────┴─────────────┘ 

实际启动示例:Raspberry Pi 4

# 编译过程 $ makeARCH=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. 设备树不匹配的症状

症状 可能原因 ────────────────────────────────────────────────────── 内核panic,找不到根文件系统 内存地址配置错误 某个外设不工作 设备树节点缺失或配置错误 内核无法启动,卡在early boot 设备树格式错误或版本不兼容 

2. 调试命令和工具

U-Boot 中的设备树操作:
# 查看设备树 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 内核中的设备树查看:
# 查看系统中的设备树 $ 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)

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

原设备树DTB + 叠加overlay.dtbo = 新配置 ↓ ↓ 基础硬件配置 特定扩展板配置 

六、最佳实践和开发建议

设备树编写原则:

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

工作流程图解:

U-Boot测试

内核测试

硬件设计完成

编写设备树.dts

编译测试

U-Boot能初始化硬件

内核能识别所有外设

验证通过

产品发布

硬件变更

仅修改.dts文件

重新编译dtb

更新启动介质

无需重新编译内核

总结:核心要点回顾

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

一句话概括:

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

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

Read more

用说话的方式训练出全能AI [特殊字符],接入飞书、Teams等办公套件,成为全能助手,SQL查数、数据分析、制作PPT等说话就行,Openclaw[特殊字符]

搭建了最近大火的openclaw框架,现在已经成了我的本地全能助手,发微博、做PPT、写代码、维护服务器等全不在话下 真的很强,代替了我大部分的日常任务 训练历程 - 零代码自然语言培养 整个过程真的很神奇,可以不用写代码,只用日常对话就把OpenClaw从基础聊天机器人培养成了全能助手! 第一阶段:基础能力建设(2026年初) 刚开始时,OpenClaw只会简单聊天。通过对话教它: * "你需要学会文件管理,帮我整理文档" * "建立记忆系统,记住重要的决定和偏好"  * "掌握飞书文档操作,方便我们协作" Openclaw,会自动阅读官方文档,进行自我迭代、总结,从而进化出你要求的技能。 神奇的是,这些复杂的技能都是通过自然语言指令实现的!不需要写一行代码,只需要告诉OpenClaw想要什么功能,它就能自动写代码、试错、迭代、总结创建对应的技能系统。 第二阶段:智能协作优化 随着OpenClaw能力的增强,开始优化它的工作方式: * "

By Ne0inhk

2024最新版Node.js下载安装及环境配置教程【保姆级】

一、进入官网地址下载安装包 Node.js 中文网 选择对应你系统的Node.js版本,这里我选择的是Windows系统、64位 二、安装程序 (1)下载完成后,双击安装包,开始安装Node.js (2)直接点【Next】按钮,此处可根据个人需求修改安装路径,修改完毕后继续点击【Next】按钮 (3)可根据自身需求进行,此处我选择默认安装,继续点击【Next】按钮 (4)不选中,直接点击【Next】按钮 (5)点击【Install】按钮进行安装 (6)安装完毕,点击【Finish】按钮 (7)测试安装是否成功,按下【win+R】键,

By Ne0inhk
Spring MVC 响应处理:页面、数据与状态配置详解

Spring MVC 响应处理:页面、数据与状态配置详解

个人主页:♡喜欢做梦 欢迎  👍点赞  ➕关注  ❤️收藏  💬评论 目录 🍋响应 🍊定义 🍊返回静态页面 🍋返回数据:@ResponseBody 🍓 @ResponseBody和@RestController的区别 🍋返回JSON 🍋状态码 🍍状态码的定义 🍍设置状态码 🍋设置header 🍋综合性练习 🍉加法计算器 🍉用户登入 🍋响应 🍊定义 响应(Response)是接收方(服务器、服务或设备)针对发送方(客户端)发起的“请求”所返回的反馈信息。 🍊返回静态页面 html代码: <!DOCTYPE html> <html lang="en"> <head&

By Ne0inhk
RabbitMQ用法的6种核心模式全面解析

RabbitMQ用法的6种核心模式全面解析

文章目录 * **一、RabbitMQ核心架构解析** * 1. AMQP协议模型 * 2. 消息流转原理 * **二、六大核心用法详解** * **1. 简单队列模式(Hello World)** * **2. 工作队列模式(Work Queues)** * **3. 发布/订阅模式(Pub/Sub)** * **4. 路由模式(Routing)** * **5. 主题模式(Topics)** * **6. RPC模式(远程调用)** * **三、高级特性实战** * **1. 消息持久化** * **2. 死信队列(DLX)** * **3. 延迟队列(插件实现)** * **四、集群与高可用方案** * 1. 镜像队列配置 * 2. 联邦跨机房部署 * **五、性能调优指南** * **六、

By Ne0inhk