跳到主要内容

用 U-Boot 通过网络启动 Linux

网络启动是嵌入式 Linux 开发中非常常用的能力。你可以把 kernel、DTB、initramfs 放在主机目录中,让 U-Boot 通过 TFTP 下载,然后启动 Linux。这样每次修改内核或设备树后,不必反复写 SD card 或 eMMC。

网络启动尤其适合内核和设备树调试。你只需要替换主机 TFTP 目录中的文件,再让 U-Boot 重新下载启动,省去了反复制作和烧写启动介质的时间。

1. 网络启动需要什么

最小网络启动链路包括:

  • U-Boot 中可用的网卡驱动。
  • IP 地址配置。
  • 一台 TFTP server。
  • kernel、DTB,可选 initramfs。

在 QEMU 用户网络中,主机通常可以通过 10.0.2.2 被 guest 访问。你可以把它作为 serverip

# [U-Boot]
setenv serverip 10.0.2.2
setenv ipaddr 10.0.2.15

如果当前网络环境支持 DHCP,也可以尝试:

# [U-Boot]
dhcp

QEMU 用户网络的 10.0.2.2 是一个特殊约定,表示 guest 访问宿主机的地址。真实开发板没有这个默认地址,你需要根据自己的局域网设置 serveripipaddr,或者使用 DHCP。

2. QEMU 中启用 TFTP 目录

启动 QEMU 时,可以让用户网络内置一个 TFTP 根目录:

# [Host]
qemu-system-aarch64 \
-machine virt \
-cpu cortex-a57 \
-m 1024 \
-nographic \
-bios u-boot.bin \
-netdev user,id=net0,tftp=/home/rudy/workspace/Projects/GetIoT/uboot-courses/tftpboot \
-device virtio-net-device,netdev=net0

然后你可以把 Imageqemu-arm64.dtbinitramfs.cpio.gz 放入 tftpboot 目录。

使用配套实验仓库时,目录通常是:

# [Host]
cd /home/rudy/workspace/Projects/GetIoT/uboot-courses
mkdir -p tftpboot

把启动文件放进去:

# [Host]
cp /path/to/Image tftpboot/
cp /path/to/qemu-arm64.dtb tftpboot/

如果暂时没有 Linux kernel 和 DTB,可以先完成 U-Boot 网络命令的认识,等准备好文件后再做完整启动。

3. 检查网络状态

进入 U-Boot 后,先查看网络相关变量:

# [U-Boot]
printenv ipaddr serverip ethaddr

设置 QEMU 用户网络常用地址:

# [U-Boot]
setenv serverip 10.0.2.2
setenv ipaddr 10.0.2.15

如果支持 ping,可以测试:

# [U-Boot]
ping ${serverip}

注意,有些 QEMU 用户网络或 U-Boot 配置下 ICMP 行为可能受限制。ping 失败不一定等于 TFTP 必定失败,但它仍然是一个很有用的初步检查。

4. 使用 TFTP 加载文件

# [U-Boot]
setenv serverip 10.0.2.2
setenv ipaddr 10.0.2.15
setenv kernel_addr_r 0x40200000
setenv fdt_addr_r 0x4fa00000

tftpboot ${kernel_addr_r} Image
tftpboot ${fdt_addr_r} qemu-arm64.dtb
setenv bootargs "console=ttyAMA0 root=/dev/vda2 rw rootwait"
booti ${kernel_addr_r} - ${fdt_addr_r}

使用 initramfs 时:

# [U-Boot]
setenv ramdisk_addr_r 0x4fb00000
tftpboot ${ramdisk_addr_r} initramfs.cpio.gz
setenv ramdisk_size ${filesize}
setenv bootargs "console=ttyAMA0"
booti ${kernel_addr_r} ${ramdisk_addr_r}:${ramdisk_size} ${fdt_addr_r}

你可以把 TFTP 启动和磁盘启动对照起来看:

动作磁盘启动网络启动
加载 kernelload virtio 0:1 ... /boot/Imagetftpboot ... Image
加载 DTBload virtio 0:1 ... /boot/qemu-arm64.dtbtftpboot ... qemu-arm64.dtb
启动命令bootibooti

也就是说,网络启动只改变“文件从哪里来”,并不改变 booti 的基本含义。

5. 常见问题

No ethernet found 说明当前 U-Boot 没有识别到网卡。检查 QEMU 是否添加了网络设备、U-Boot 配置是否启用了对应驱动、dm tree 中是否能看到网络设备。

TFTP error: File not found 说明文件不在 TFTP 根目录,或者文件名大小写不匹配。TFTP 路径通常相对于 TFTP 根目录,不要写主机绝对路径。

一直超时时,检查 serveripipaddr、QEMU 网络参数和防火墙。如果使用外部 TFTP server,还要确认服务监听地址和权限。

DHCP 后变量被改了

执行 dhcp 后,U-Boot 可能会更新 ipaddrserveripbootfile 等变量。你可以在 DHCP 后重新 printenv 查看:

# [U-Boot]
dhcp
printenv ipaddr serverip bootfile

如果 DHCP 给出的 serverip 不是你的 TFTP server,就需要手动改回去。

TFTP 下载成功但启动失败

说明网络传输已经通过。后面继续按普通启动排查:kernel 格式、DTB、地址、bootargs、rootfs。

6. 网络启动与 NFS root

开发内核时,常见组合是 kernel 和 DTB 通过 TFTP 下载,rootfs 通过 NFS 挂载。对应 bootargs 类似:

# [U-Boot]
setenv bootargs "console=ttyAMA0 root=/dev/nfs nfsroot=10.0.2.2:/path/to/rootfs,tcp ip=dhcp"

NFS root 涉及主机导出目录、内核 NFS 支持和网络参数,本教程这里只建立概念。实际使用时请结合 Linux 内核文档和你的发行版 NFS server 配置。

与 TFTP 不同,NFS root 是 Linux kernel 启动后的事情。U-Boot 只负责把 nfsroot=ip= 等参数传给 Linux;真正挂载 NFS root 的是 Linux。

7. 安全提醒

TFTP 没有认证和加密,适合受控开发网络,不适合直接暴露到不可信网络。产品升级和安全启动不要依赖裸 TFTP 作为唯一保护机制。

本章小结

网络启动能显著提高开发效率。排查时按“网卡是否存在、IP 是否正确、文件是否可访问、启动参数是否正确”逐层检查。

思考与练习

  1. 解释 QEMU 用户网络中 10.0.2.2 的含义。
  2. 使用 TFTP 下载一个 DTB,并用 fdt header 验证。
  3. 对比 load virtiotftpboot,说明它们改变的是启动链中的哪一环。