嵌入式 Linux 启动流程详解 (以 ARM + U-Boot 为例)

对于嵌入式开发者而言,深入理解系统的启动流程至关重要。这不仅有助于进行底层驱动开发和系统移植,还能在遇到启动失败等问题时,快速定位和解决。本文将详细分解基于 ARM 架构的嵌入式 Linux 系统最常见的启动流程:BootROM -> U-Boot -> Kernel -> RootFS。过段时间仔细研究一下Uboot,看看能不能给手上这块3506移植个Uboot试试。


在这里插入图片描述

启动流程总览

嵌入式设备的启动过程是一个环环相扣的链条,前一级加载器负责初始化基础硬件,并加载下一级更复杂的程序,直到最终启动完整的 Linux 操作系统。

graph TDsubgraph SoC 内部芯片A[电源开启] --> B(BootROM);endsubgraph 引导加载程序 (Bootloader)B --> |从 Flash/SD卡 加载| C[U-Boot SPL];C --> |初始化DDR| D[U-Boot 主体];endsubgraph 内核与用户空间D --> |执行 bootcmd| E[加载 Linux 内核 (zImage)];D --> |执行 bootcmd| F[加载设备树 (DTB)];E & F --> G{启动内核};G --> H[内核初始化硬件];H --> I[挂载根文件系统 (RootFS)];I --> J[执行第一个用户进程 /sbin/init];J --> K[启动系统服务与应用];end

1. BootROM - 芯片内的第一行代码

BootROM 是整个启动链的起点。

  • 是什么:一段固化在 SoC (System on Chip) 芯片内部的只读存储器 (ROM) 中的程序。它由芯片制造商编写,用户无法修改,是上电后 CPU 执行的第一段代码
  • 核心职责
    1. 最小化硬件初始化:进行最基础的硬件设置,如配置内部时钟、初始化用于加载下一阶段代码的存储接口(如 SD 卡控制器、eMMC、SPI Flash 等)。
    2. 加载外部引导程序:根据预设的启动介质顺序(通常由一组 BOOT_MODE 引脚的电平状态决定),从外部存储设备(Flash, eMMC, SD Card)中查找并加载第二阶段的引导加载程序(通常是 U-Boot 的一个小型版本 SPL)到芯片内部的 SRAM 中。
    3. 移交控制权:加载完成后,将 CPU 的执行权限交给这段刚刚加载进来的代码。

BootROM 的工作非常单一,就是为更强大的 Bootloader 搭建一个最小化的运行环境。


2. U-Boot - 通用引导加载程序

U-Boot (Universal Boot Loader) 是嵌入式领域应用最广泛的开源引导加载程序。它功能强大,通常分两个阶段执行,以适应嵌入式系统 SRAM 较小的限制。

2.1 第一阶段: U-Boot SPL (Secondary Program Loader)

  • SPL 是什么:一个精简版的 U-Boot,主要目的是初始化 DDR 内存。由于 BootROM 加载 SPL 时使用的是芯片内部的 SRAM,而 SRAM 通常很小(几十到几百 KB),无法容纳完整的 U-Boot。
  • 核心职责
    1. 初始化 DDR 控制器:这是 SPL 最重要的任务。DDR 内存是运行 Linux 内核和应用程序所必需的大容量内存空间。
    2. 加载 U-Boot 主体:DDR 初始化完成后,SPL 会从外部存储设备中将完整的 U-Boot 镜像 (u-boot.img) 加载到 DDR 内存中。
    3. 跳转执行:将控制权移交给位于 DDR 中的 U-Boot 主体。

2.2 第二阶段: U-Boot 主体

这是我们通常所说的 U-Boot,它功能完善,为启动 Linux 内核提供了所有必要的准备。

  • 核心职责
    1. 全面的硬件初始化:初始化系统所需的各种外设,如串口(用于打印启动日志和提供命令行交互)、网络接口(用于网络启动和调试)、存储设备(eMMC, NAND)等。
    2. 设置内核启动参数 (bootargs):这是 U-Boot 的一个关键功能。它会设置一个名为 bootargs 的环境变量,然后将其传递给 Linux 内核。这个参数字符串告诉内核一些重要的初始配置,例如:
      • console=ttyS0,115200:指定内核使用哪个串口作为控制台,以及波特率。
      • root=/dev/mmcblk0p2 rootwait:指定根文件系统的位置(例如在 SD 卡的第 2 个分区),并让内核等待设备就绪。
      • rootfstype=ext4:指定根文件系统的类型。
    3. 加载内核和设备树:根据 bootcmd 环境变量中定义的命令(或手动输入),从存储介质(或通过网络 TFTP)中将 Linux 内核镜像 (zImage) 和设备树文件 (.dtb) 加载到 DDR 内存的指定地址。
    4. 启动内核:执行 bootzbootm 命令,将设备树文件的内存地址传递给内核,然后跳转到内核的入口点,正式开始 Linux 系统的启动。

3. Linux Kernel - 操作系统的核心

内核接管控制权后,标志着真正的操作系统开始运行。

  1. 内核自解压zImage 是一个压缩的镜像,所以第一步是在内存中将自己解压出来。
  2. 解析设备树 (DTB):内核会读取 U-Boot 传递过来的 DTB 文件。DTB 描述了板级的所有硬件信息,内核根据这些信息来初始化对应的驱动程序。这使得内核代码可以与硬件解耦,一份内核源码可以适配不同的开发板。
  3. 初始化硬件:内核开始全面初始化由 DTB 描述的所有硬件设备,并建立起驱动模型、内存管理、进程调度等核心子系统。
  4. 挂载根文件系统 (RootFS):内核根据 bootargs 中的 root 参数,找到并挂载根文件系统。
    • 在开发阶段,常常使用 NFS (Network File System),方便快速修改和调试。
    • 在量产产品中,根文件系统通常存放在 eMMC 或 Flash 的一个分区上,格式为 ext4, squashfs (只读压缩), ubifs (用于 NAND Flash) 等。
  5. 启动 init 进程:根文件系统被挂载后,内核会创建并运行第一个用户空间的进程 /sbin/init(其 PID 永远为 1)。内核的初始化工作到此结束,后续的用户空间初始化全权交由 init 进程处理。

4. Init 与用户空间

init 进程是所有用户空间进程的“始祖”。它的任务是根据配置文件,将系统带入一个可用的状态。

  • 常见的 init 程序:
    • BusyBox init:在资源受限的嵌入式系统中非常流行。它解析 /etc/inittab 文件,按顺序执行其中的脚本来启动系统服务。
    • SystemV init:传统的 init 系统,同样使用 /etc/inittab 和运行级别 (Runlevel) 脚本 (/etc/rc.d/)。
    • systemd:现代 Linux 发行版的主流选择,功能强大,并行启动速度快,但在嵌入式领域有时被认为过于复杂和庞大。
  • 执行流程init 进程会运行一系列启动脚本,这些脚本会:
    • 挂载其他必要的文件系统(如 /proc, /sys, /tmp)。
    • 配置网络。
    • 启动系统日志、SSH 服务等后台守护进程。
    • 最终,启动核心的应用程序

当用户的应用程序成功运行起来后,整个嵌入式 Linux 系统的启动流程便宣告完成。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/web/95954.shtml
繁体地址,请注明出处:http://hk.pswp.cn/web/95954.shtml
英文地址,请注明出处:http://en.pswp.cn/web/95954.shtml

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

在前端开发中,html中script 的type分别有哪几种?分别什么情况用到?

以下是 HTML 中<script>标签type属性的常见取值、说明及使用场景&#xff1a;type 值说明使用场景不写&#xff08;空值&#xff09;HTML5 中默认等同于text/javascript&#xff0c;表示普通 JavaScript 脚本绝大多数传统 JavaScript 代码&#xff0c;包括内联脚本和外部…

2025职教技能大赛汽车制造与维修赛道速递-产教融合实战亮剑​

各位职教同仁&#xff0c;2025年世界职业院校技能大赛总决赛争夺赛&#xff08;汽车制造与维修赛道&#xff09;国内赛区的战报新鲜出炉&#xff01;本次大赛以“技炫青春 能创未来”为主题&#xff0c;聚焦汽车产业链高质量发展需求&#xff0c;在真实场景中比拼技能&#xff…

日志 | Spring Boot 日志配置通用规律(AI问答)

Spring Boot 日志配置通用规律。想看特定日志&#xff0c;怎么打开日志开关 文章目录一、一句话总结二、AI问答版提问词AI的响应&#x1f4ca; Spring Boot 日志配置通用规律1. 基本语法结构2. 日志级别&#xff08;从详细到简洁&#xff09;&#x1f3af; 常用日志配置分类1. …

DJANGO后端服务启动报错及解决

1.报错信息[2025-09-05 17:08:54 0800] [23438] [INFO] Worker exiting (pid: 23438) [2025-09-05 17:08:54 0800] [23440] [ERROR] Exception in worker process Traceback (most recent call last):File "/www/SOP/lib64/python3.11/site-packages/gunicorn/arbiter.py&…

Qt 中的 Q_OBJECT 宏详解 —— 从源码到底层机制的全面剖析

Qt 中的 Q_OBJECT 宏详解 —— 从源码到底层机制的全面剖析 文章目录Qt 中的 Q_OBJECT 宏详解 —— 从源码到底层机制的全面剖析摘要一、Q_OBJECT 宏是什么&#xff1f;二、Q_OBJECT 宏背后的源码三、moc 工具的作用四、信号与槽调用流程五、没有 Q_OBJECT 会怎样&#xff1f;六…

GD32自学笔记:5.定时器中断

定时器中断功能主要是两点&#xff1a;1.怎么配置的定时器中断时间间隔&#xff1b;2.中断里长什么样一、定时器中断配置函数直接在bsp_basic_timer.c里找到下面函数&#xff1a;void basic_timer_config(uint16_t pre,uint16_t per) {/* T 1/f, time T * pre,pertime (pre …

[Godot入门大全]目录

1 免责声明 资源分享免责声明&#xff1a; 本平台/本人所分享的各类资源&#xff08;包括但不限于文字、图片、音频、视频、文档等&#xff09;&#xff0c;均来源于公开网络环境中的可分享内容或已获授权的传播素材。 本平台/本人仅出于信息交流、资源共享之目的进行传播&…

使用 StringRedisTemplate 实现 ZSet 滚动查询(处理相同分数场景)

1. 为什么需要改进当 ZSet 中存在相同分数 (score) 的元素时&#xff0c;单纯使用分数作为偏移会导致数据漏查或重复。例如&#xff1a;多条记录具有相同时间戳&#xff08;作为分数&#xff09;分页查询时可能跳过相同分数的元素或重复查询相同分数的元素改进方案&#xff1a;…

【Android】安装2025版AndroidStudio开发工具开发老安卓旧版App

为了开发老旧的安卓App&#xff0c;这里记录一下2025版AndroidStudio的安装过程&#xff0c;如果卸载以后&#xff0c;可以按照此文章的步骤顺利重新安装继续使用。 文章目录安装包Android SDK新建项目新建页面构建项目Gradle下载失败构建失败构建完成编译失败安装失败关于APP在…

Python跳过可迭代对象前部元素完全指南:从基础到高并发系统实战

引言&#xff1a;跳过前部元素的核心价值在数据处理和系统开发中&#xff0c;跳过可迭代对象的前部元素是常见且关键的操作。根据2024年数据处理报告&#xff1a;92%的数据清洗需要跳过文件头部85%的日志分析需要忽略初始记录78%的网络协议处理需跳过头部信息65%的机器学习训练…

ConcurrentHashMap扩容机制

ConcurrentHashMap的扩容为了提高效率&#xff0c;是多线程并发的每个线程控制一部分范围节点的扩容(根据cpu与数组长度确定控制多大范围)有两个核心参数sizeCtl&#xff1a;标记扩容状态 负数时代表正在扩容&#xff0c;存储量参与扩容的线程数&#xff0c;正数代表出发扩容的…

Spring Cloud Gateway 进行集群化部署

如果将 Gateway 单独部署为一个服务而不做任何高可用处理&#xff0c;它确实会成为一个单点故障&#xff08;SPOF, Single Point of Failure&#xff09;。如果这个唯一的 Gateway 实例因为服务器宕机、应用崩溃、部署更新或其他任何原因而不可用&#xff0c;那么整个系统的所有…

计算机网络:以太网中的数据传输

以太网中&#xff0c;数据的传输依赖于一系列标准化的技术规范&#xff0c;核心包括帧结构封装、介质访问控制机制和物理层编码技术&#xff0c;具体如下&#xff1a; 1. 以“帧&#xff08;Frame&#xff09;”为基本传输单元 以太网在数据链路层将网络层的数据包&#xff08;…

元器件--USB TypC接口

USB TypC接口下图这些都是USB接口A口与B口的区别USB A口和B口最初由USB-IF在1996年引入。根据当时的USB协议&#xff0c;A口主要用于主设备&#xff08;如电脑&#xff09;&#xff0c;而B口则用于从设备&#xff08;如打印机和摄像头&#xff09;。随着USB-C接口的日益普及&am…

多线程之HardCodedTarget(type=OssFileClient, name=file, url=http://file)异常

多线程之HardCodedTarget(typeOssFileClient, namefile, urlhttp://file)异常 摘要&#xff1a; 文档描述了多线程环境下调用Feign客户端OssFileClient时出现的HardCodedTarget异常。异常发生在异步保存文件到ES时&#xff0c;Feign调用未返回预期结果而直接打印了客户端对象。…

计算机视觉(十二):人工智能、机器学习与深度学习

人工智能 (AI)&#xff1a;宏大的目标 人工智能是最广泛、最宏大的概念&#xff0c;它的目标是让机器能够模仿人类的智能行为&#xff0c;例如&#xff1a; 推理&#xff1a;像下棋程序一样&#xff0c;通过逻辑来做决策。规划&#xff1a;为实现一个目标而制定步骤&#xff0c…

容器元素的滚动条回到顶部

关闭再打开后&#xff0c;容器元素的滚动条回到顶部解决方法&#xff1a;1、通过打开开发者工具&#xff08;F12&#xff09;&#xff0c;找到滚动条所属元素为 el-textarea__inner&#xff0c;其父类 class"el-textarea content"2、代码&#xff0c;通过元素的方法 …

分布式专题——2 深入理解Redis线程模型

1 Redis 简介 1.1 Redis 是什么&#xff1f; Redis 全称 Remote Dictionary Server&#xff08;远程字典服务&#xff09;&#xff0c;是一个开源的高性能 Key-Value 数据库&#xff1b; 官网&#xff1a;Redis - The Real-time Data Platform&#xff1b; 引用官网上的⼀个…

simd学习

如何查看cpu是否支持simd&#xff1f;# 检查特定指令集 grep -o avx2 /proc/cpuinfo | head -1 # 检查AVX2 grep -o sse4 /proc/cpuinfo | head -1 # 检查SSE4 grep -o avx512 /proc/cpuinfo | head -1 # 检查AVX512gcc编译选项&#xff0c;增加支持simd-mavx2 -D__AVX2__SS…

LabVIEW汽车发动机振动测试

以某型号四缸汽油发动机为测试对象&#xff0c;借助 LabVIEW 平台与高精度数据采集硬件&#xff0c;开展发动机全工况振动测试。通过实时采集缸体、曲轴箱关键部位振动信号&#xff0c;分析振动特征与故障关联&#xff0c;验证发动机运行稳定性&#xff0c;为后期优化设计提供数…