跳到主要内容

用 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 访问宿主机的地址。真实开发板没有这个默认地址,你需要根据自己的局域网设置 serverip 和 ipaddr,或者使用 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

然后你可以把 Image、qemu-arm64.dtb、initramfs.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 根目录,不要写主机绝对路径。

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

DHCP 后变量被改了​

执行 dhcp 后,U-Boot 可能会更新 ipaddr、serverip、bootfile 等变量。你可以在 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 virtio 和 tftpboot,说明它们改变的是启动链中的哪一环。