☰
嵌入式启动流程与 Uboot 参数传递
2026/10/14 21:12:35 网站建设 项目流程

一、嵌入式启动流程

1,运行厂家固化在芯片内部irom的代码

初始化基本的硬件设备时钟等

判断启动方式(emmc,SD卡,USB)

把Bootloader 第一阶段的代码加载到IRAM(芯片内运行内存)(不做内存初始化)

2,运行Bootloader第一阶段代码

SPL:u-boot-spl.bin

初始化整个系统的时钟,以及必要的配置;

初始化板子内存

把完整的Bootloader搬移到DDR中

分两部分是因为芯片内存小,需要分一小部分初始化基本的配置以及内存,以在内存加载完整的Bootloader。

3,在内存中加载Bootloader第二阶段代码

初始化具体的硬件配置(根据板子定义,如网卡,串口,USB等);

4、加载操作系统 5、挂载文件系统 6、启动应用程序

二、U-boot和Linux 内核之间的参数传递

当开发板上电后,Bootloader启动,初始化对应的配置,而Linux内核是被动被u-boot拉起来的,不知道相应的硬件配置信息(内存大小、根文件系统位置、启动参数等),所以需要对Linux内核传递参数才能正确启动硬件系统。

寄存器
r0规定为0
r1开发板的ID
r2

其他参数在内存中开始地址

u_boot和Linux之间在传递参数的时候,一般按照双方约定的格式传递,比如1.struct parm__struct结构体,2.tag列表,3.设备树.

U-Boot 环境变量 bootcmd 与 bootargs 详解

bootcmd 决定 U-Boot 自己如何加载并启动内核,bootargs 决定 U-Boot 启动内核时给内核传入哪些启动参数。

1. bootcmd:U-Boot 自身的启动命令

bootcmd 是 U-Boot 在启动倒计时结束后自动执行的一组命令,相当于 U-Boot 的开机自启动脚本。它通常负责从网络、EMMC 或 SD 卡把内核镜像和设备树加载到内存,再通过 bootm 命令启动内核。

bootcmd=tftp 41000000 uImage;tftp 42000000 exynos4412-fs4412.dtb;bootm 41000000 - 42000000

2. bootargs:传给 Linux 内核的启动参数

bootargs 是 U-Boot 告诉内核根文件系统在哪里、控制台用哪个串口、网络如何配置等。

bootargs=root=/dev/nfs nfsroot=192.168.2.128:/home/hqyj/fs4412/rootfs,proto=tcp,nfsvers=3,nolock rw console=ttySAC2,115200 init=/linuxrc ip=192.168.2.152:192.168.2.128:192.168.2.1:255.255.255.0::eth0:off
参数含义
root=/dev/nfs根文件系统通过 NFS 网络文件系统挂载
nfsroot=192.168.2.128:/home/hqyj/fs4412/rootfsNFS 服务器 IP 为 192.168.2.128,共享目录为 /home/hqyj/fs4412/rootfs
proto=tcp,nfsvers=3,nolockNFS 使用 TCP 协议、版本 3,并且不加文件锁
rw根文件系统以可读写方式挂载
console=ttySAC2,115200内核控制台使用串口 ttySAC2,波特率为 115200
init=/linuxrc内核启动后运行的第一个用户态进程是 /linuxrc
ip=192.168.2.152:192.168.2.128:192.168.2.1:255.255.255.0::eth0:off静态配置网络:开发板 IP 192.168.2.152,服务器 192.168.2.128,网关 192.168.2.1,掩码 255.255.255.0,网卡 eth0,off 表示不自动配置

三、Linux 内核编译驱动原理讲解(Kconfig Makefile .config menuconfig之间的关系)

1. Kconfig:内核编译前,menuconfig 会递归读取各级 Kconfig 生成配置菜单。

Kconfig生效需要在上一级目录source包含(source "drivers/char/test/Kconfig")

2. .config:保存最终配置结果

make menuconfig 进行配置后,系统会把用户的选择写入内核源码根目录下的 .config 文件中。

3. Makefile:根据 .config 决定编译内容

obj-$(CONFIG_MY_DRIVER) += my_driver.o

4. menuconfig:Linux内核提供的可视化菜单配置,显示内核支持的功能

四、u-boot启动流程

U-Boot 的启动流程整体上可以分为两个阶段:第一阶段主要完成 CPU 级初始化和内存初始化;第二阶段完成板级外设初始化、环境变量加载以及内核引导。

由于芯片内部 RAM 容量有限,通常先由固化在 IROM 中的代码加载 SPL,由 SPL 初始化时钟和 DDR,再把完整的 U-Boot 搬移到 DDR 中运行。

board_init_f 阶段准备重定位环境,relocate_code 进行代码重定位,board_init_r 阶段完成网卡、串口、USB 等外设初始化,最后进入 main_loop 主循环。

进入 main_loop 后,U-Boot 会等待倒计时;若超时,则自动执行 bootcmd 中配置的命令,把内核镜像和设备树加载到内存,并按照 bootargs 把根文件系统、控制台和网络参数传递给 Linux 内核,最终通过 bootm 命令完成内核启动。

所以简述U-Boot 启动流程:一是 SPL 让内存可用,加载u-boot到内存;二是 U-Boot 完成自身重定位;三是 bootcmd 与 bootargs 协作,把控制权交给 Linux 内核。

五、Linux启动流程分析

Linux 内核被 U-Boot 加载到内存后,启动流程大致分为以下几个阶段:

  1. 内核自解压与入口执行:内核镜像被加载到内存后,首先执行入口代码,完成内核压缩镜像的解压,为后续运行准备环境。
  2. 汇编阶段初始化:关闭中断、初始化页表、使能 MMU,并根据启动参数完成基本的硬件相关初始化。
  3. C 语言阶段初始化:进入start_kernel后,依次完成进程管理、内存管理、文件系统、设备驱动等子系统初始化。
  4. 挂载根文件系统:根据 U-Boot 传入的bootargs参数,挂载真实的根文件系统。
  5. 启动用户态 init 进程:内核启动第一个用户态进程,通常为init或linuxrc,由它继续完成系统服务和应用程序的启动。

六、busybox init启动流程

  • 挂载根文件系统: 让 Linux 能访问根目录下的程序、配置文件和系统工具。

  • 启动 init 进程: 启动用户空间的第一个进程(PID 1),负责组织系统初始化。

  • 读取/etc/inittab: 根据配置确定系统启动时启动脚本程序

    (id编号:权限等级):动作:进程

    ::sysinit:/etc/init.d/rcS # 系统初始化最先执行rcS脚本(最关键) ::askfirst:-/bin/sh # 串口控制台拉起一个shell交互终端 ::restart:/sbin/init # init异常重启的处理 ::ctrlaltdel:/sbin/reboot # 按键重启系统
  • 执行/etc/init.d/rcS: 执行系统初始化脚本,完成基础环境

    #!/bin/sh /bin/mount -a # 根据 /etc/fstab 挂载所有文件系统 mkdir /dev/pts # 创建伪终端设备目录 mount -t devpts devpts /dev/pts # 挂载 devpts 文件系统(支持 SSH 等需要终端的程序) echo /sbin/mdev>/proc/sys/kernel/hotplug # 告诉内核:有热插拔事件时调用 mdev mdev -s # 扫描 /sys 创建所有设备节点(/dev/ttySAC2 等)
  • 挂载/etc/fstab指定的文件系统: 挂载各种文件系统等,为系统提供内核信息接口和运行空间。/proc/sys/tmp

    /proc:内核运行信息虚拟文件系统
    /sys:硬件设备树、驱动信息文件系统
    /tmp:临时目录(内存文件系统)
    /dev:设备节点目录

  • 启动 Shell 程序: 提供命令行交互环境,让用户能够输入命令、运行程序。

  • 执行/etc/profile: 设置 、、命令提示符等环境变量,准备 Shell 的使用环境。PATHHOME


库是什么

库(Library)是一组预先编译好的、可复用的代码集合,把常用的函数、类或数据封装起来,供多个程序共享调用。

动态库和静态库的区别

对比项静态库动态库
常见后缀.a(Linux)、.lib(Windows).so(Linux)、.dll(Windows)
链接时机编译链接时,把库代码直接复制进可执行文件程序运行时才加载,可执行文件只记录库的引用
可执行文件大小较大,因为包含了库代码较小,库代码不打包进程序
部署与更新更新库需要重新编译整个程序替换库文件即可生效,无需重新编译程序
内存占用每个程序各持有一份库代码,内存占用高多个程序可共享同一份库,内存占用低
依赖风险无运行时依赖,程序独立性强运行时依赖库文件,缺失或版本不匹配会导致程序无法启动

如何链接库
-L:指定库的搜索路径(去哪里找.a/.so)
-lxxx:指定链接libxxx.so或者libxxx.a gcc 优先找动态库.so;想强制静态链接加‑static。

操作系统如何知道加载库的路径

  1. 编译时通过-Wl,-rpath指定的路径(优先级最高);

  2. 环境变量LD_LIBRARY_PATH指定的路径;

  3. /etc/ld.so.cache中缓存的路径,该缓存由/etc/ld.so.conf配置生成,修改配置后需运行ldconfig更新缓存;

  4. 系统默认目录/lib和/usr/lib


程序被杀死后,如何自动重启

1.init进程启动的过程中,读取/etc/inittab文件,并且将这个文件指定的程序启动起来。
::respawn:(程序杀死会被拉起)

2.shell 脚本监控​(/etc/init.d/rcS)或者/etc/profile文件添加

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询