Linux驱动 2026年4月21日 27 分钟

uboot中的bootargs和bootcmd

# U-Boot 中的 bootcmd 和 bootargs 详解 在嵌入式 Linux 开发中,尤其是内核、设备树和驱…

# U-Boot 中的 bootcmd 和 bootargs 详解

在嵌入式 Linux 开发中,尤其是内核、设备树和驱动开发过程中,经常会接触到 **`bootcmd`****`bootargs`**。它们都不是 Linux shell 命令,而是 **U-Boot 的环境变量**

很多初学者容易把它们混淆,其实它们分别解决的是两个不同的问题:

**`bootcmd`**:U-Boot 如何启动 Linux

**`bootargs`**:Linux 内核启动时携带哪些参数

## 1. bootcmd 是什么

`bootcmd` 表示:

> **U-Boot 倒计时结束后默认自动执行的启动命令。**

它的作用是决定:

– 从哪里加载内核镜像

– 从哪里加载设备树文件 `dtb`

– 是否加载 `initrd/initramfs`

– 最终调用 `bootz`、`bootm` 还是 `booti` 启动内核

可以把它简单理解为:

> **“U-Boot 怎样把 Linux 启动起来”**

## 2. bootargs 是什么

`bootargs` 表示:

> **传递给 Linux 内核的启动参数。**

它的作用是决定内核启动后的运行方式,例如:

– 串口控制台是谁

– 根文件系统在哪里

– 根文件系统是只读还是读写

– 是否启用早期调试输出

– 网络参数如何设置

– 是否通过 NFS 启动

– 某些内建驱动的启动参数

可以把它理解为:

> **“Linux 内核启动时带哪些参数运行”**

## 3. bootcmd 和 bootargs 的关系

系统启动流程大致是:

“`text

上电

 -> BootROM

 -> U-Boot

 -> 执行 bootcmd

 -> bootcmd 加载内核和设备树

 -> U-Boot 将 bootargs 传给 Linux 内核

 -> Linux 内核启动

 -> 驱动初始化/probe

“`

所以两者关系很清晰:

**`bootcmd`**:决定“如何启动内核”

**`bootargs`**:决定“内核启动后按什么参数运行”

## 4. 在驱动开发中为什么重要

### 4.1 bootcmd 很重要

在驱动开发里,`bootcmd` 决定:

– 你加载的是不是最新编译的 `zImage`

– 你加载的是不是最新修改过的 `.dtb`

– 加载地址是否正确

– 启动方式是否正确

很多时候你以为驱动代码没生效,其实不是驱动有问题,而是 **U-Boot 启动的根本不是你刚更新的内核或设备树**

### 4.2 bootargs 很重要

在驱动开发里,`bootargs` 直接影响:

– 串口日志能不能看到

– 根文件系统能不能挂载成功

– 网络根文件系统能不能启动

– 调试参数是否打开

– 是否能看到更早期的启动日志

常见调试参数例如:

“`bash

console=ttymxc0,115200

loglevel=8

ignore_loglevel

initcall_debug

earlycon

“`

这些对调试驱动初始化、probe 顺序、卡死位置等都很有帮助。

## 5. 你的参数示例

你当前给出的参数是:

“`bash

bootargs=console=ttymxc0,115200 root=/dev/nfs nfsroot=192.168.10.100:/home/eh/linux/nfs/xuexi/rootfs,proto=tcp rw ip=192.168.10.50:192.168.10.100:192.168.10.1:255.255.255.0::eth0:off

bootcmd=tftp 80800000 zImage;tftp 83000000 imx6ull-alientek-emmc.dtb;bootz 80800000 – 83000000

“`

这是一种非常典型的开发模式:

> **通过 TFTP 下载内核和设备树,通过 NFS 挂载根文件系统。**

也就是:

> **TFTP 启动内核 + NFS 根文件系统启动**

## 6. 你的 bootcmd 逐项解释

“`bash

bootcmd=tftp 80800000 zImage;tftp 83000000 imx6ull-alientek-emmc.dtb;bootz 80800000 – 83000000

“`

它可以拆成 3 步。

### 6.1 `tftp 80800000 zImage`

意思是:

– 通过 **TFTP** 从服务器下载 `zImage`

– 下载到内存地址 **0x80800000**

这里的 `zImage` 就是 Linux 内核镜像。

### 6.2 `tftp 83000000 imx6ull-alientek-emmc.dtb`

意思是:

– 通过 **TFTP** 从服务器下载设备树文件 `imx6ull-alientek-emmc.dtb`

– 下载到内存地址 **0x83000000**

这个 `.dtb` 文件描述开发板硬件信息。

### 6.3 `bootz 80800000 – 83000000`

意思是:

– 使用 `bootz` 启动 **zImage 格式** 的内核

– 内核地址是 **0x80800000**

– 中间的 `-` 表示 **没有 initrd/initramfs**

– 设备树地址是 **0x83000000**

### 6.4 整个 bootcmd 的含义

把三步连起来就是:

> **U-Boot 先通过 TFTP 下载内核和设备树到内存,然后启动 Linux。**

## 7. 你的 bootargs 逐项解释

“`bash

bootargs=console=ttymxc0,115200 root=/dev/nfs nfsroot=192.168.10.100:/home/eh/linux/nfs/xuexi/rootfs,proto=tcp rw ip=192.168.10.50:192.168.10.100:192.168.10.1:255.255.255.0::eth0:off

“`

它是传给 Linux 内核的启动参数。

### 7.1 `console=ttymxc0,115200`

意思是:

– Linux 控制台输出到 `ttymxc0`

– 串口波特率为 `115200`

作用:

– 你在串口终端上看到的内核启动日志主要依赖它

– 驱动里的 `printk` 输出通常也通过这里查看

### 7.2 `root=/dev/nfs`

意思是:

– 根文件系统不是本地存储设备

– 而是通过 **NFS 网络文件系统** 挂载

这表示 Linux 启动后会把网络服务器上的某个目录作为根目录 `/` 使用。

### 7.3 `nfsroot=192.168.10.100:/home/eh/linux/nfs/xuexi/rootfs,proto=tcp`

意思是:

– NFS 服务器地址:`192.168.10.100`

– 根文件系统目录:`/home/eh/linux/nfs/xuexi/rootfs`

– 挂载 NFS 时使用 `TCP` 协议

也就是说,Linux 的根文件系统来自:

“`bash

192.168.10.100:/home/eh/linux/nfs/xuexi/rootfs

“`

### 7.4 `rw`

意思是:

– 根文件系统以 **读写方式** 挂载

如果写成 `ro`,则表示只读挂载。

### 7.5 `ip=192.168.10.50:192.168.10.100:192.168.10.1:255.255.255.0::eth0:off`

这是给 Linux 内核设置网络参数的。

格式大致是:

“`bash

ip=<本机IP>:<服务器IP>:<网关IP>:<子网掩码>:<主机名>:<网卡名>:<自动配置方式>

“`

你的参数展开后含义如下:

**本机 IP**:`192.168.10.50`

**服务器 IP**:`192.168.10.100`

**网关 IP**:`192.168.10.1`

**子网掩码**:`255.255.255.0`

**主机名**:空

**网卡名**:`eth0`

**自动配置方式**:`off`

其中 `off` 表示:

– 不使用 DHCP

– 不使用 BOOTP

– 不使用 RARP

– 直接采用写死的静态 IP 配置

所以这是一种:

> **静态 IP + NFS 挂载根文件系统** 的启动方式。

## 8. 把你的参数整体连起来理解

你的系统启动流程实际上是这样的。

### 在 U-Boot 阶段

1. 通过 TFTP 下载 `zImage`

2. 通过 TFTP 下载 `imx6ull-alientek-emmc.dtb`

3. 用 `bootz` 启动内核

### 在 Linux 内核阶段

1. 从 `ttymxc0` 串口输出启动日志

2. 使用静态 IP:`192.168.10.50`

3. 与服务器 `192.168.10.100` 通信

4. 通过 NFS 挂载服务器目录 `/home/eh/linux/nfs/xuexi/rootfs`

5. 把这个目录作为 Linux 根文件系统 `/`

所以一句话总结你的配置就是:

> **通过 TFTP 启动内核和设备树,通过 NFS 挂载根文件系统。**

### 8.1 为什么内核和设备树常用 TFTP,而根文件系统常用 NFS

这不是“必须这样”,而是因为 **TFTP 和 NFS 更适合不同阶段的任务**

#### 1)为什么启动阶段常用 TFTP

U-Boot 处在系统刚上电后的早期阶段,这时它的能力比较有限,通常只有一个比较简化的网络协议栈。

TFTP 的特点是:

– 协议简单

– 实现开销小

– 很适合按文件名下载少量文件

– 非常适合传输 `zImage`、`uImage`、`.dtb` 这类单个启动文件

所以在 bootloader 阶段,TFTP 非常适合用来做:

– 下载内核镜像

– 下载设备树

– 有时也下载 initramfs

简单说就是:

> **U-Boot 阶段更需要“把几个启动文件快速搬到内存里”,TFTP 正适合做这件事。**

#### 2)为什么根文件系统常用 NFS

根文件系统不是一个单独文件,而是一整套目录树,里面包含:

– `/bin`

– `/sbin`

– `/lib`

– `/etc`

– `/dev`

– `/usr`

– 各种配置、脚本、库文件、可执行程序

Linux 启动后,需要把这些内容当成一个真正的文件系统来访问,要求支持:

– 目录层级

– 按路径查找文件

– 权限管理

– 符号链接

– 动态库加载

– 按需读写文件

而 NFS 的本质就是:

> **把服务器上的一个目录,通过网络挂载成 Linux 可直接使用的文件系统。**

所以它非常适合做 rootfs。

#### 3)为什么不能把 rootfs 也直接用 TFTP

因为 TFTP 本质上只是一个 **文件传输协议**,不是一个真正的“可挂载文件系统”。

它适合做的是:

– 下载一个文件

– 再下载另一个文件

但它不适合做的是:

– 让 Linux 把它当 `/` 根目录来长期运行

– 支持成千上万个文件的按需访问

– 提供完整文件系统语义

所以:

> **TFTP 适合传文件,不适合直接充当运行中的根文件系统。**

当然,也有一种特殊情况:

– 先通过 TFTP 下载一个 `initramfs` 镜像

– 再由内核把这个镜像当临时根文件系统使用

但这本质上是“**TFTP 下载一个 rootfs 镜像到内存**”,不是“**把 TFTP 本身当 rootfs 文件系统**”。

#### 4)那能不能都用 NFS

理论上可以,前提是你的 U-Boot 编译时支持 `nfs` 命令。

也就是说,在某些环境里,U-Boot 也可以通过 NFS 去取:

– 内核镜像

– 设备树文件

但是实践中更常见的还是:

**U-Boot 用 TFTP 拉内核和 dtb**

**Linux 用 NFS 挂载 rootfs**

原因是:

– TFTP 在 bootloader 阶段更简单直接

– 配置和调试成本更低

– 兼容性通常更好

– 传少量启动文件已经足够

#### 5)一句话理解分工

你可以这样记:

**TFTP**:适合启动阶段“搬运几个文件到内存”

**NFS**:适合系统运行阶段“把整个目录树当文件系统来使用”

所以你现在这种方案本质上是:

> **启动文件传输用 TFTP,运行时根文件系统访问用 NFS。**

这是一种按协议特点做的分工,而不是随意搭配。

## 9. 为什么这种方式特别适合驱动开发

这种启动方式对驱动开发非常方便,原因包括:

### 9.1 改内核方便

你重新编好 `zImage` 后,只要更新服务器上的内核镜像,开发板下次启动就能用新内核。

### 9.2 改设备树方便

你修改并重新编译 `.dtb` 后,只要更新 TFTP 服务器上的 dtb 文件即可。

### 9.3 改根文件系统方便

因为根文件系统走 NFS,所以:

– 改应用程序

– 改脚本

– 改库文件

– 改测试程序

都不需要反复烧写 eMMC/SD 卡,只要直接改服务器目录内容即可。

### 9.4 调试效率高

非常适合:

– 内核开发

– 设备树调试

– 驱动开发

– 根文件系统调试

## 10. 一个容易误解的地方

你的设备树文件名是:

“`bash

imx6ull-alientek-emmc.dtb

“`

而你的根文件系统却是:

“`bash

root=/dev/nfs

“`

这两者并不矛盾。

因为:

– `imx6ull-alientek-emmc.dtb` 描述的是板级硬件平台

– `root=/dev/nfs` 决定的是 Linux 最终从哪里挂载根文件系统

也就是说:

> **你这块板是 eMMC 版本硬件,但当前调试时根文件系统走的是 NFS。**

这是完全正常的。

## 11. 在实际开发中如何查看和修改

### 查看当前值

“`bash

printenv bootcmd

printenv bootargs

“`

### 修改当前值

“`bash

setenv bootcmd ‘tftp 80800000 zImage; tftp 83000000 imx6ull-alientek-emmc.dtb; bootz 80800000 – 83000000’

setenv bootargs ‘console=ttymxc0,115200 root=/dev/nfs nfsroot=192.168.10.100:/home/eh/linux/nfs/xuexi/rootfs,proto=tcp rw ip=192.168.10.50:192.168.10.100:192.168.10.1:255.255.255.0::eth0:off’

“`

### 保存环境变量

“`bash

saveenv

“`

如果不执行 `saveenv`,很多情况下修改只在本次上电有效,重启后可能丢失。

## 12. 一句话区分

你可以这样记:

**`bootcmd`**:U-Boot 执行的“启动脚本”

**`bootargs`**:传给 Linux 内核的“启动参数”

## 13. 总结

在 Linux 驱动开发中:

**怀疑启动的不是最新内核或最新 dtb,看 `bootcmd`**

**怀疑日志、根文件系统、网络启动、调试参数有问题,看 `bootargs`**

对于你当前这套参数,完整含义是:

> **U-Boot 通过 TFTP 下载 `zImage``dtb` 到内存中启动 Linux;Linux 内核通过静态 IP 与 NFS 服务器通信,并将服务器上的 rootfs 目录挂载为根文件系统。**

这是一种非常典型、非常适合内核和驱动开发的启动方式。

上一篇 广告机实战项目

下一篇 Linux文件检索

# Linux 文件检索命令 ## 目录 – [find 命令](#一find-命令) – [g...