uboot环境变量设置

Tutorial: 卓越工程师 Category: 嵌入式 Published: 2026-10-23 11:05:29 Views: 1 Likes: 0 Comments: 0

339.3.12 U-Boot 环境变量设置

本节没有编写 C 程序、驱动源码或设备树源码,因此标题下不添加臆造的 C 代码。本节要把上一课搭好的开发板专用网络真正用于网络启动:U-Boot 先通过 TFTP 把 Linux 内核 zImage 和设备树 topeet_emmc_hdmi.dtb 下载到 DDR,随后启动内核;Linux 内核再通过 NFS 把 Ubuntu 中的 ~/nfs 挂载为根文件系统。

Ubuntu/TFTP/NFS 服务器(192.168.2.220)
          │
          ├── TFTP ──> U-Boot 将 zImage、DTB 下载到开发板 DDR
          │
          └── NFS  ──> Linux 内核把 /home/wfeng/nfs 挂成根文件系统
                                  │
                                  └── 开发板(192.168.2.120)

必须先分清三个阶段:U-Boot 负责设置环境变量和下载启动文件;bootz 把控制权交给 Linux;NFS 根文件系统由已经启动的 Linux 内核挂载,不是 U-Boot 把整个根文件系统下载到内存。TFTP 成功只能证明启动文件可下载,不能证明 NFS 一定可用。

视频中的实验环境为 i.MX6ULL 开发板、512 MiB DDR、U-Boot 2016.03,网络设备输出为 FEC1;串口终端使用 MobaXterm、CH340 串口和 115200 波特率。下面的文件名、内存地址和网卡名都与这块板的课程配置绑定,不能不加核对地照搬到其他板卡。

一、U-Boot 网络配置

1.1 流程详解

开发板上电后,U-Boot 在自动启动前显示 3 秒倒计时。在倒计时归零前按任意键,进入 => 提示符;若不打断,U-Boot 会执行 bootcmd。U-Boot 官方文档也将 bootcmd 定义为启动延时结束后自动执行的命令,将 bootargs 定义为传给操作系统的命令行参数,见 U-Boot 环境变量说明。

=> ?             # 列出当前构建实际支持的命令;help 具有相同用途
=> printenv      # 打印全部环境变量
=> printenv ipaddr serverip netmask gatewayip ethaddr
                 # 只查看本节关心的网络变量,输出更容易核对

命令所在的终端必须分清:

提示符/界面执行内容本节典型命令
Ubuntu Shell准备 TFTP 文件、解压根文件系统、管理 NFS 服务cp、tar、exportfs
U-Boot 串口 =>配置板卡、TFTP 下载、启动内核setenv、saveenv、tftp、bootz
Linux 启动日志/登录口内核启动及根文件系统中的用户空间Welcome to topeet!、登录提示

1.2 修改网络相关环境变量

视频逐条设置的网络变量是:

=> setenv serverip 192.168.2.220
=> setenv gatewayip 192.168.2.1
=> setenv ipaddr 192.168.2.120
=> setenv netmask 255.255.255.0
=> setenv ethaddr 42:03:07:3B:15:5F
变量视频中的值准确含义与注意事项
serverip192.168.2.220TFTP/NFS 所在 Ubuntu 的地址;U-Boot 官方说明中,serverip 是 TFTP 服务器地址
ipaddr192.168.2.120U-Boot 阶段开发板自己的地址
netmask255.255.255.0即 /24;使 .120、.220、.223 位于同一 192.168.2.0/24 子网
gatewayip192.168.2.1U-Boot 的网关变量;只有访问其他子网时才需要真实网关
ethaddr42:03:07:3B:15:5F开发板以太网 MAC 地址;必须在同一二层网络中唯一

上一课的拓扑是开发板、Windows 物理网卡和 Ubuntu 第二网卡处于同一子网,并没有证据表明 192.168.2.1 上存在路由器。因此,本实验的 TFTP/NFS 流量不经过网关,gatewayip 可以不设;若要跨网段,才应填入实际可达的路由器地址。

视频在修改前曾打印出另一条 ethaddr=08:07:03:A0:03:22,随后又将其改成 42:03:07:3B:15:5F。不要把课程 MAC 批量复制到多块板上:重复 MAC 会让交换机和主机的邻居表不断改变。若板卡已有厂家分配且有效的 MAC,应优先保留;若实验中必须自定义,要保证唯一。0x42 的最低位为 0,表示单播;次低位为 1,表示本地管理地址,但“本地管理”仍不等于可以重复使用。

设置后应立即核对,避免把变量名或地址输错:

=> printenv serverip gatewayip ipaddr netmask ethaddr

setenv 修改的是当前运行时环境,命令执行后已经可以用于本次网络操作;此时尚未持久化。

1.3 保存环境变量

正确命令是 saveenv,不是原笔记 OCR 识别出的“c5 env”:

=> saveenv
Saving Environment to MMC...
Writing to MMC(1)... done

画面中的存储介质是 MMC/eMMC,不是“emsa”;结束信息是 done,不是“down”。saveenv 将当前环境保存到板卡为 U-Boot 环境预留的非易失存储区,使断电后仍能恢复。官方 env 命令文档说明,env save 会把环境保存到持久化介质,saveenv 是兼容别名,见 U-Boot env 命令。

重启不是让变量“开始生效”的必要条件;变量在 setenv 后已作用于当前会话。这里重启的意义是验证保存结果,并让自动启动流程重新读取并执行新 bootcmd。

1.4 重启 U-Boot 网络设置

=> reset

reset 会立即复位开发板。重新出现倒计时后按任意键,再用 printenv 检查保存的变量是否仍在。若只是想继续手动测试网络,不需要为了每次改动都复位;如果已经设置了新的 bootcmd,复位后又没有打断倒计时,它会直接进入自动下载和启动流程。

不要把在终端软件里按 Ctrl+A、Ctrl+C 当成“进入 U-Boot 设置模式”的固定组合。本视频真正依赖的是板卡复位/执行 reset,并在 U-Boot 倒计时期间按键。Ctrl+C 在 U-Boot 网络命令持续重试时可用于中止当前命令。

1.5 网络测试

视频在 U-Boot 中测试了 Ubuntu、Windows 以及一个没有回应的地址:

=> ping 192.168.2.220
Using FEC1 device
host 192.168.2.220 is alive

=> ping 192.168.2.223
Using FEC1 device
host 192.168.2.223 is alive

=> ping 192.168.2.222
ARP Retry count exceeded; starting again
ping failed; host 192.168.2.222 is not alive

成功提示是 host ... is alive,不是 OCR 识别出的“all love love”。失败时 U-Boot 可能反复尝试 ARP,可按 Ctrl+C 中止。U-Boot 官方网络测试会以 host is alive 作为 ping 成功依据,见 U-Boot 网络测试说明。

Windows 主动 ping 192.168.2.120 在视频中没有收到响应,但这不能被解释成“失败反而证明网络已经通”。很多 U-Boot 构建只在执行网络命令时轮询和处理网络包,停在普通命令提示符时未必持续响应主机发来的 ICMP Echo。正确结论是:

  • U-Boot 主动 ping Ubuntu/Windows 成功,证明该次 ARP 与 ICMP 往返成功;
  • Windows 主动 ping U-Boot 失败,单凭这一项无法判定断线还是 U-Boot 未响应;
  • 后面的 TFTP 实际下载成功,才进一步验证 U-Boot 到服务器的 UDP/TFTP 路径、服务和文件访问都可用。

1.6 修改 U-Boot 引导方式

视频要把默认从 eMMC 读取内核/DTB 的流程,改为“U-Boot 从 TFTP 取内核和 DTB,Linux 从 NFS 挂根文件系统”。画面中实际输入的两条命令如下:

=> setenv bootcmd 'tftp 80800000 zImage; tftp 83800000 topeet_emmc_hdmi.dtb; bootz 80800000 - 83800000'
=> setenv bootargs 'console=ttymxc0,115200 root=/dev/nfs rw nfsroot=192.168.2.220:/home/wfeng/nfs ip=192.168.2.120:192.168.2.220:192.168.2.1:255.255.255.0::eth0:off'

bootcmd 中三条子命令按顺序执行:

  1. tftp 80800000 zImage:从 serverip 下载内核到 DDR 地址 0x80800000;
  2. tftp 83800000 topeet_emmc_hdmi.dtb:下载 eMMC+HDMI 版本的 DTB 到 0x83800000;
  3. bootz 80800000 - 83800000:从第一个地址启动 zImage,- 表示没有 initrd,第三个参数是设备树地址。

这里必须用 bootz,原笔记写成 bootm 是错误的。U-Boot 官方 bootz 文档明确说明它用于启动 zImage,并规定没有 initrd、但要传 DTB 时用 - 占据第二个参数。地址省略了 0x,但在 U-Boot 命令语境中作为十六进制地址使用。这些地址是课程板卡的既定内存布局;换板或换镜像必须根据该板的 U-Boot 配置、DDR 范围和镜像大小重新确认,避免镜像互相覆盖或落到不可用内存。

bootargs 是传给 Linux 内核的一整行启动参数:

字段含义
console=ttymxc0,115200将内核控制台放在 i.MX 的第 1 个 UART,波特率 115200
root=/dev/nfs告诉内核根文件系统来自 NFS;/dev/nfs 是选择 NFS 根的伪设备名,不是真实块设备
rw以可读写方式挂载根文件系统
nfsroot=192.168.2.220:/home/wfeng/nfsNFS 服务器地址和服务端导出的根目录
ip=...配置 Linux 启动阶段的客户端 IP、服务器 IP、网关、掩码、主机名、网卡和自动配置方式

Linux 内核官方文档给出的格式是:

nfsroot=[<server-ip>:]<root-dir>[,<nfs-options>]
ip=<client-ip>:<server-ip>:<gw-ip>:<netmask>:<hostname>:<device>:<autoconf>

其中网关只在服务器位于不同子网时需要,完整解释见 Linux 内核 NFS 根文件系统文档。本课三端同属 /24,若 192.168.2.1 并不存在,更严谨的客户端参数应把网关字段留空;这会在服务器地址后连续出现两个冒号:

=> setenv bootargs 'console=ttymxc0,115200 root=/dev/nfs rw nfsroot=192.168.2.220:/home/wfeng/nfs,v3,tcp ip=192.168.2.120:192.168.2.220::255.255.255.0::eth0:off'

这条改进写法还显式请求 NFSv3/TCP。视频中板卡原有默认环境的 netargs 本来就包含 nfsroot=${serverip}:${nfsroot},v3,tcp,说明该 BSP 预期使用 v3;显式协商客户端版本通常比为了旧客户端去扩大服务器的 NFSv2 暴露更清晰。若课程内核不识别 v3 简写,可依据它所配套的内核文档改用标准挂载选项 vers=3,tcp,不能只靠猜测反复改服务端。

1.7 文件系统、内核拷贝

视频中的内核源码树位于:

~/Linux/kernel/linux-imx-rel_imx_4.1.15_2.1.0_ga

在 Ubuntu Shell 中把编译产物放进上一课配置的 TFTP 根目录 ~/tftpfile:

# 进入 ARM 内核启动镜像所在目录。
cd ~/Linux/kernel/linux-imx-rel_imx_4.1.15_2.1.0_ga/arch/arm/boot

# 复制已编译的 zImage 到 TFTP 根目录。
cp zImage ~/tftpfile/

# 进入设备树编译产物目录。
cd dts

# 视频用通配符筛选 HDMI 版本;Linux 文件名区分大小写,应使用小写 hdmi。
ls *hdmi*.dtb

# eMMC 板选择 eMMC+HDMI 的 DTB;不要误选 NAND 版本。
cp topeet_emmc_hdmi.dtb ~/tftpfile/

# 核对 U-Boot 将要请求的两个精确文件名、大小和时间。
ls -lh ~/tftpfile/zImage ~/tftpfile/topeet_emmc_hdmi.dtb

画面中的筛选结果同时包含 topeet_emmc_hdmi.dtb 和 topeet_nand_hdmi.dtb,本课程是 eMMC 板,所以选择前者。原笔记的 /tftp/ 与画面不符;本课程实际 TFTP 根目录是 ~/tftpfile。bootcmd 中的文件名必须与该目录下的大小写完全一致。

二、U-Boot 环境变量设置

2.1 U-Boot 环境变量设置操作

在把命令写入 bootcmd 前,视频先做了逐步手动测试:

=> tftp 80800000 zImage
TFTP from server 192.168.2.220; our IP address is 192.168.2.120
Load address: 0x80800000
Bytes transferred = 7186568 (6da888 hex)

=> tftp 83800000 topeet_emmc_hdmi.dtb
TFTP from server 192.168.2.220; our IP address is 192.168.2.120
Load address: 0x83800000
Bytes transferred = 40551 (9e67 hex)

=> bootz 80800000 - 83800000

这组结果分别证明:服务器和网络可达;TFTP 根目录中存在两个文件;U-Boot 能把它们放到指定地址;bootz 开始运行 Linux。官方下载测试也将“完成下载,并校验得到的大小或 CRC”作为 TFTP 成功条件,见 U-Boot 网络测试文档。

第一次手动执行时并没有先设置有效的 bootargs,内核最终输出:

VFS: Cannot open root device "(null)" or unknown-block(0,0): error -6
Kernel panic - not syncing: VFS: Unable to mount root fs on unknown-block(0,0)

这不是 bootz 或 TFTP 失败,而是内核没有得到有效的根文件系统位置。只有同时准备好 rootfs、导出 NFS 目录并传入正确 bootargs,内核才可能继续进入用户空间。

2.2 NFS 挂载失败问题分析

排障时要按启动阶段读最后一条明确错误,不能把所有故障都统称为“内核没起来”:

已出现的现象已经成功的部分下一步应查
Bytes transferred = ...U-Boot 的网卡、TFTP 服务、文件名和下载地址基本可用bootz 参数、镜像匹配关系
Starting kernel ... 后出现 Linux 驱动日志U-Boot 已把控制权交给 Linux,内核能够执行内核命令行、网络驱动、NFS
root device "(null)"内核已运行bootargs 是否存在 root=/dev/nfs、nfsroot=、ip=
Unable to mount root fs via NFS内核已尝试 NFS 根服务版本、导出路径、权限、rootfs 内容、网络中断

视频开始时 ~/nfs 为空,这确实意味着还没有可用的根文件系统内容;但“目录为空”和“没有传 bootargs”是两个独立问题,不能用其中一个替代另一个。上一课还必须已经在 /etc/exports 中导出 /home/wfeng/nfs,并让配置真正生效。

2.3 U-Boot 默认环境变量

2.3.1 恢复默认环境的正确含义

视频演示了恢复默认环境的命令:

=> env default -a
=> saveenv

env default -a 会把 全部 环境变量在内存中恢复为 U-Boot 编译时默认值;saveenv 才把这一结果持久化。它会覆盖网络地址、MAC、bootcmd、bootargs 等自定义配置,不是普通“刷新”操作。执行前应先用 printenv 保存或抄录现有配置。若只想恢复某个变量,应先查当前 U-Boot 的 env default 帮助,不应无条件使用 -a。

2.3.2 准备课程 rootfs 压缩包

本小节标题沿用原笔记,但视频后半段实际还讲了 rootfs 的获取。课程从配套资料取得 rootfs.tar.bz2,再通过 Samba 或 FileZilla 复制到 Ubuntu 的 ~/nfs。传输工具只负责搬运文件,不能证明这个同名压缩包就是本板卡、该内核所需的版本;复制后应记录来源并校验哈希:

# 记录压缩包大小、时间以及 SHA-256,便于与课程发布值核对。
ls -lh ~/nfs/rootfs.tar.bz2
sha256sum ~/nfs/rootfs.tar.bz2

2.4 ping 虚拟机与 Windows

本标题沿用原始笔记;虚拟机与 Windows 的 ping 已在 1.5 节核准,本段视频画面实际主要在解压 rootfs。rootfs.tar.bz2 是 bzip2 压缩的 tar 归档,GNU tar 在很多版本中可由文件内容自动识别压缩格式,所以视频中的 tar -xvf 能工作;写出 j 更明确:

# 先只列目录,确认归档没有额外套一层错误目录,并检查路径是否异常。
tar -tjf ~/nfs/rootfs.tar.bz2 | head

# 进入 NFS 导出目录后,以 root 权限保留数字 UID/GID、权限和符号链接进行解压。
cd ~/nfs
sudo tar --numeric-owner -xvjpf rootfs.tar.bz2

# 根目录内容应直接出现 bin、etc、lib、linuxrc 等,而不是再嵌套一层 rootfs/。
ls -la

嵌入式根文件系统依赖文件所有者、执行权限、符号链接,某些归档还可能包含特殊设备节点,因此不能只看“文件解出来了”。压缩包应来自可信来源;在成功启动、哈希核对和备份完成前不要急着删除原包。若重新解压不同版本,最好先准备一个新的空导出目录,防止旧文件与新文件混合,造成更难判断的“半新半旧”系统。

2.5 最后一步配置

手动 TFTP 和 bootz 验证完成后,复位开发板、在倒计时期间按键回到 =>,再将已验证的启动链写入环境变量。视频原样命令是:

=> setenv bootcmd 'tftp 80800000 zImage; tftp 83800000 topeet_emmc_hdmi.dtb; bootz 80800000 - 83800000'
=> setenv bootargs 'console=ttymxc0,115200 root=/dev/nfs rw nfsroot=192.168.2.220:/home/wfeng/nfs ip=192.168.2.120:192.168.2.220:192.168.2.1:255.255.255.0::eth0:off'

若采用本笔记前面建议的同子网、NFSv3/TCP 写法,则只替换第二条为:

=> setenv bootargs 'console=ttymxc0,115200 root=/dev/nfs rw nfsroot=192.168.2.220:/home/wfeng/nfs,v3,tcp ip=192.168.2.120:192.168.2.220::255.255.255.0::eth0:off'

粘贴长命令后不要立刻保存,先回读:

=> printenv bootcmd bootargs

重点逐字符检查 DTB 文件名、三处内存地址、NFS 路径、IP 字段中的冒号数量以及 ttymxc0 的大小写。终端自动换行只是显示效果,不代表变量中真的插入了换行。

2.6 设置环境变量并保存

确认无误后执行:

=> saveenv
Saving Environment to MMC...
Writing to MMC(1)... done

原笔记再次出现的 c5 env 仍是 OCR 错误。若 saveenv 报错,不能假定已经持久化;应检查 U-Boot 为环境配置的存储设备/分区以及 MMC 写入状态。保存成功后也可以再次 printenv bootcmd bootargs,留存串口记录,便于故障时确认板卡到底用了什么参数。

2.7 重置开机

=> reset

这次不要按键打断倒计时,U-Boot 会自动执行 bootcmd:每次从 ~/tftpfile 下载当前的 zImage 和 DTB,再启动 Linux;Linux 随后从 Ubuntu 的 ~/nfs 使用根文件系统。这正是驱动开发方便之处:

  • 重新编译内核/设备树后,把新产物覆盖到 TFTP 根目录,下次启动即可下载;
  • 修改 rootfs 中的应用、脚本或库后,开发板通过 NFS 直接看到服务端文件;
  • 这并不意味着所有修改都能热生效:已加载的内核、DTB 和正在运行的进程不会因为服务端文件变化自动重载,相关修改仍需重启或重启进程;
  • 覆盖启动文件前建议保留可回退版本和哈希,防止新镜像导致板卡无法启动。

2.8 内核无法启动问题分析

视频将问题与“课程原环境是 Ubuntu 16,而当前使用 Ubuntu 20”联系起来,这只是排查线索,不是完整因果关系。主机桌面版本本身不会直接决定板卡 Linux 能否执行;真正需要核对的是主机所带 NFS 服务端默认启用哪些协议版本、板端 4.1.15 内核支持并请求什么版本、导出规则是否生效,以及 rootfs 是否正确。

把故障写成“Ubuntu 20 不支持 NFSv2,只支持 3/4”也过于绝对。Ubuntu 20.04 的 nfs-utils/内核组合可能不默认提供某些旧协议,而不同更新和配置会改变实际启用集合;更新的 Ubuntu 中 NFSv2 又可能已经彻底移除。应查看运行中的事实,而不是只凭发行版名称:

# 查看内核 NFS 服务端当前启用/禁用的版本;+ 表示启用,- 表示禁用。
cat /proc/fs/nfsd/versions

# 查看 RPC 注册的 NFS、mountd 等服务和协议。
rpcinfo -p localhost

# 查看真正生效的导出规则。
sudo exportfs -v

# 查看服务状态和本次启动日志。
systemctl status nfs-kernel-server --no-pager
journalctl -u nfs-kernel-server -b --no-pager

Ubuntu 的 nfsstat 手册说明 nfsstat -s 可只显示服务端统计,并可按 v2/v3/v4 区分,见 Ubuntu 20.04 nfsstat(8)。启动开发板前后比较计数,还能判断请求是否真的抵达服务器。

2.9 U-Boot 通过 NFS 挂根文件系统时,加载完内核后卡死在这里

这个原题目的说法需要纠正:U-Boot 通过 TFTP 加载内核和 DTB;进入 Starting kernel ... 后,是 Linux 内核尝试通过 NFS 挂根文件系统。视频后续出现的关键日志是:

VFS: Unable to mount root fs via NFS, trying floppy.
VFS: Cannot open root device "nfs" or unknown-block(2,0): error -6

此时内核已经运行,故障位于 Linux 网络/NFS 根阶段。“卡死”也不够准确:画面最终进入 kernel panic,是内核明确终止启动,而不是无日志地停住。应向上查找同一段日志中的 IP-Config、网卡 link、NFS 服务器响应、超时和拒绝信息,再结合服务端日志定位。

2.10 U-Boot 通过 NFS 挂载根文件系统卡死解决办法

视频参考网上资料,在 Ubuntu 的 /etc/default/nfs-kernel-server 末尾加入:

RPCNFSDOPTS="--nfs-version 2,3,4 --debug --syslog"

然后重启 NFS 服务。这里应将它记录为视频尝试过的兼容性排查手段,而不是普适答案:--nfs-version 请求服务端提供指定版本,--debug 开启调试消息,--syslog 将消息写入系统日志。Ubuntu 的 rpc.nfsd 手册说明这些参数控制服务端提供的 NFS 版本和日志方式;同时,较新的实现已经只支持主要版本 3、4,说明硬编码开启 v2 并不具备长期兼容性,见 Ubuntu rpc.nfsd(8)。

修改后必须验证服务是否接受配置,而不是只看文件已保存:

sudo systemctl restart nfs-kernel-server
systemctl status nfs-kernel-server --no-pager
cat /proc/fs/nfsd/versions
sudo exportfs -v

若服务启动失败,应恢复错误参数并查看日志。长期保留 --debug 会增加日志量;问题定位完可以去掉。NFS/TFTP 都没有传输加密和强身份保护,本实验服务应只暴露在隔离的板卡开发网,不应直接开放到不可信网络。

2.11 问题解决

课程讲解把上述配置理解为“强制使用 NFSv2”,但该字符串实际上请求服务端尝试提供 2、3、4;能否真正启用仍取决于本机 rpc.nfsd 和内核。更稳妥的解决顺序是:

  1. 优先在客户端 nfsroot 中显式使用本 BSP 默认环境已经采用的 ,v3,tcp;
  2. 用 /proc/fs/nfsd/versions、rpcinfo -p 和 nfsstat -s 核对服务端事实;
  3. 用 exportfs -v 确认 /home/wfeng/nfs 对开发板地址或板卡子网真正导出;
  4. 从启动日志区分“无服务器响应”“被拒绝”“协议不支持”“路径不存在”和“rootfs 无法执行”;
  5. 只有证据表明板端只能发出 v2 请求、且服务端确实还能安全启用 v2 时,才把启用 v2 作为临时兼容措施。

Linux 官方 NFS 根文档允许在 nfsroot= 后附加标准 NFS 选项,因此在客户端固定版本和传输协议是有文档依据的。服务端配置不是本节唯一变量:视频在做完版本修改后仍然没有立即启动成功,不能声称这一步已经单独解决全部问题。

2.12 问题解决后重启开机

服务端配置、导出目录和 rootfs 都确认后,重启 NFS 服务,再复位板卡观察完整日志。真正证明 NFS 根已挂上的关键行是:

VFS: Mounted root (nfs filesystem) on device 0:14.

后续出现:

Welcome to topeet!
iTOP_imx6ul/ull login:

才说明内核已经执行根文件系统中的初始化程序并到达登录界面。视频中还出现过:

nfs: server 192.168.2.220 not responding, still trying
nfs: server 192.168.2.220 OK

两行合起来表示服务器一度超时、随后恢复响应;只截取第一行会误判为永久失败。仍应检查虚拟机负载、桥接网卡、线缆和服务端日志,避免把偶发恢复当成健康状态。

2.13 问题最终定位

视频最终发现存在两个同名 rootfs.tar.bz2,画面先展示了约 18 MB 的包,随后指向约 1.92 MB 的课程包并说明后者才是这次应使用的文件。替换并重新解压正确 rootfs 后,系统最终到达登录提示。因此本次实际排障至少包含两个相互独立的变量:NFS 协议/服务端配置,以及 rootfs 包选错。还要注意,错误的 rootfs 内容通常会导致挂载后的 init、动态库或用户空间启动失败,不能单独解释此前发生在协议层的“NFS 根无法挂载”;视频的先后变化能证明换包参与了解决过程,却不能证明它是每一条早期报错的唯一原因。不能把结论简单归纳成“只要打开 NFSv2”或“只要改权限”。

文件大小只能帮助识别本次画面中的两个包,不是通用真伪标准。可靠做法是使用课程发布位置、版本说明和 SHA-256 校验值;压缩包即使能解压,也可能属于另一块板、另一套 libc/ABI 或不同初始化系统。

成功进入登录界面后,视频日志仍出现了这些警告:

modprobe: can't change directory to '/lib/modules': No such file or directory
Starting network: ip: RTNETLINK answers: File exists FAIL

第一条表示 rootfs 中没有与当前内核匹配的 /lib/modules/<kernel-release>,需要把本次内核编译产生的模块安装到根文件系统,或确认系统根本不依赖可加载模块。第二条常见于内核已按 ip= 配好 eth0,用户空间启动脚本又重复添加地址/路由;它不等于 NFS 挂载失败,但应清理重复网络配置。画面中的蓝牙固件报错也属于外围功能问题,不能用“已到登录界面”掩盖。

最终建议按下表验收,而不是只看某一个提示:

检查点正确证据常见错误方向
U-Boot 网络ping 服务器成功IP/掩码、桥接、MAC 冲突、线缆
TFTP 内核文件名、字节数和装载地址正确TFTP 根目录、大小写、错误镜像
bootz出现 Starting kernel ... 和 Linux 日志地址重叠、内核/DTB 不匹配、错误命令
Linux 静态网络IP-Config 显示 .120/.220 和正确掩码ip= 字段错位、错误网卡名/网关
NFS 服务请求到达,导出规则与协议匹配服务未启动、版本不匹配、导出路径/权限
NFS 根挂载VFS: Mounted root (nfs filesystem)rootfs 路径、协议、服务器超时
用户空间到达 login:,关键服务无致命错误错 rootfs、init/动态库/权限/模块不匹配

这套分阶段证据链比“反复 reset 看能不能碰巧启动”更可靠:先确认上一个阶段已经完成,再只排查下一层,才能快速定位网络启动问题。