跳转到内容
新建笔记

Ubuntu 虚拟机向 U-Boot 下载文件:网络与 TFTP 排查

适用场景:Ubuntu 虚拟机运行 TFTP 服务,开发板通过网线连接电脑,U-Boot 从虚拟机下载镜像到 RAM。下载成功只证明这次传输完成;是否可以启动、应写哪个存储位置,需要另行核对镜像格式和板级布局。

1. 让开发板能够到达虚拟机

跳转到“1. 让开发板能够到达虚拟机”

直连开发板时,桥接到连接开发板的那张物理网卡通常最直观。虚拟机表现为同一二层网络中的独立设备,具有独立 IP。多网卡主机应明确指定有线接口,避免自动桥接到 Wi-Fi。

网络方式默认连通范围用于此场景时的要点
桥接虚拟机与物理网卡所在网络中的设备无需 NAT 转发;交换机安全策略、无线桥接限制和虚拟化过滤驱动仍可能影响通信
NAT虚拟机通常可主动访问外部,外部不能默认主动访问虚拟机服务可用路由或端口转发实现入站,但 TFTP 还使用协商后的 UDP 端口,单转发 69 常不够
Host-only主机与同一 host-only 网络中的虚拟机彼此通信不会自动连到物理开发板;需额外路由/转发或另一网卡

因此桥接是这里的简便方案,不是实现通信的唯一方式。虚拟机也可使用两张网卡:一张 NAT 上网,一张桥接到开发板;开发板接口不要添加不需要的默认路由。

以隔离实验网段为例:

Ubuntu 虚拟机:192.168.1.100/24
开发板: 192.168.1.101/24
电脑有线口: 如需配置,另选不冲突的地址

如果电脑现有 Wi-Fi、VPN 或其他网卡已经使用 192.168.1.0/24,换用不冲突的网段,并同步修改下面各处。直连同网段通信不需要路由器、网关或 DNS。

2. 配置 Ubuntu 的开发板接口

跳转到“2. 配置 Ubuntu 的开发板接口”

先用 ip -br link、ip -br addr、ip route 确认接口名、地址和路由。已有 NetworkManager 配置的桌面系统,应继续用该管理器配置连接;不要同时让多个配置文件或管理器管理同一接口。

下面是由 Netplan / systemd-networkd 管理接口时的示例,enp0s8 必须替换为实际名称;应修改已有配置,避免新旧定义冲突。

network:
version: 2
renderer: networkd
ethernets:
enp0s8:
dhcp4: false
addresses:
- 192.168.1.100/24

在本地控制台应用前,先检查语法,再试运行:

终端窗口
sudo netplan generate
sudo netplan try
ip -br addr
ip route get 192.168.1.101

netplan try 默认在未确认时尝试回滚,但官方文档提示回滚存在已知限制。超时或取消后仍要检查实际地址以及磁盘上的配置,尤其不能把它当作远程修改网络的绝对保险。

3. 建立仅供下载的 TFTP 目录

跳转到“3. 建立仅供下载的 TFTP 目录”

Ubuntu/Debian 的 tftpd-hpa 可用于该实验:

终端窗口
sudo apt update
sudo apt install tftpd-hpa
sudo install -d -o root -g root -m 0755 /srv/tftp
# u-boot.bin 为当前目录内已经确认来源、格式的文件。
sudo install -o root -g root -m 0644 u-boot.bin /srv/tftp/u-boot.bin
sha256sum /srv/tftp/u-boot.bin
stat -c '%s bytes' /srv/tftp/u-boot.bin

编辑 /etc/default/tftpd-hpa,示例绑定开发板网络的地址:

TFTP_USERNAME="tftp"
TFTP_DIRECTORY="/srv/tftp"
TFTP_ADDRESS="192.168.1.100:69"
TFTP_OPTIONS="--secure --port-range 30000:30010"

--secure 把服务限制在共享目录内;没有 --create 时不会创建新上传文件。目录由 root 持有且只有 0755、文件为 0644,使服务用户无法写入已有文件。tftpd-hpa 默认要求供下载文件具有其他用户可读权限,因此这里采用 0644。无需 chmod 777,也无需把目录交给 nobody。不要在共享目录放凭据或其他私人文件。

终端窗口
sudo systemctl restart tftpd-hpa
sudo systemctl status tftpd-hpa --no-pager
sudo ss -lunp
sudo journalctl -u tftpd-hpa -n 50 --no-pager

TFTP 的初始请求发往 UDP 69;后续数据由服务端另外选择的传输端口发送。上例把该范围限定为 UDP 30000–30010,便于按来源地址、接口和方向制定规则。在实际防火墙中允许开发板与服务地址间这些必要的流量,或者配置能够正确跟踪 TFTP 的机制;不要为排查关闭整台电脑的防火墙。范围大小需满足并发数要求,主机和虚拟机两侧过滤也都要检查。

先执行 version、help tftpboot、bdinfo 并核对板级 RAM 布局。以下操作假定 ${loadaddr} 已设为容量足够、与 U-Boot/栈/设备树等不重叠的有效 RAM 区域。不能从别的开发板照抄地址。

printenv loadaddr ipaddr serverip netmask ethact autostart
setenv ipaddr 192.168.1.101
setenv serverip 192.168.1.100
setenv netmask 255.255.255.0
setenv autostart no
ping ${serverip}
if tftpboot ${loadaddr} u-boot.bin; then
setenv download_size ${filesize}
echo Downloaded bytes hex: ${download_size}
else
echo TFTP download failed
fi

autostart=no 防止某些配置在加载后自动启动镜像;先保留在 RAM 环境即可,不必立即 saveenv。若板上有多个网口,按 ethact、PHY 链路和实际接线选择接口。ping 成功可以确认部分 IP 连通性,但 ICMP 失败不一定意味着 TFTP 必然不可用;还要看对端是否过滤 ICMP。

只有下载成功才记录 ${filesize}。U-Boot 中它通常是十六进制长度,必须与主机的十进制文件大小按相同进制比较。后续加载其他文件会改变 ${filesize},所以应立刻另存。本例没有设置 autoload,因为没有使用会触发自动加载的 DHCP/BOOTP 流程。

有 hash 命令时,在成功分支后按目标帮助执行 hash sha256 ${loadaddr} ${download_size},与主机摘要比较。摘要相同可以帮助发现传输或内存损坏;没有可信摘要来源时不能证明镜像受信任。TFTP 本身没有身份认证和加密,适合受控开发网络。

现象优先检查
没有链路或 ARP 一直超时网线、PHY、正确的物理桥接接口、虚拟网卡是否连接、IP/掩码、重复 IP
虚拟机本机可访问,开发板不行NAT/host-only 选错,宿主过滤驱动、入站规则、路由网段冲突
请求有响应,传输开始后超时服务端传输端口、双向防火墙、NAT 跟踪;抓包确认 DATA/ACK 的端口
File not found文件实际位于 /srv/tftp 内;请求用 u-boot.bin,不加主机的绝对目录;注意大小写
Access violation文件/目录权限、服务用户和安全策略,不用开放全部写权限解决
大文件传输异常RAM 容量、传输端口、MTU/分片、协商块长、超时与重试;先用小文件定位

RFC 1350 的基本块长为 512 字节,最后一个数据块必须短于块长;文件长度恰好为块长整数倍时还需要一个零长度尾块。支持扩展的客户端/服务器可以协商更大块长,不能仅凭抓包中不是 512 字节就判定错误。

6. 下载后再决定启动或更新

跳转到“6. 下载后再决定启动或更新”

不要从“TFTP 成功”直接跳到 nand erase 或猜测 nand write.jffs2 参数。目标可能使用 SD、eMMC、SPI NOR、NAND 或 ROM 特定容器;原始 u-boot.bin 也可能缺少 SPL、启动头或平台固件。

先确认文件格式、目标介质、预留区域、长度单位和恢复入口,再按 U-Boot 加载、校验与存储更新 操作。这里验证到 RAM 下载为止,真实写入后还需要读回、启动以及失败恢复验证。