1. 项目概述
在嵌入式Linux开发中,通过网络加载内核和文件系统是提高开发效率的关键技术。本文将详细介绍如何在ARM平台上使用TFTP协议加载内核和设备树,以及通过NFS挂载根文件系统的完整流程。特别针对Ubuntu 20.04等高版本系统中常见的NFS挂载失败问题,提供经过验证的解决方案。
2. 环境准备与配置
2.1 网络环境搭建
网络连接是TFTP和NFS工作的基础,需要确保开发板与主机处于同一局域网段。建议采用以下配置:
- 开发板IP:192.168.10.50
- 主机IP:192.168.10.100
- 子网掩码:255.255.255.0
- 网关:192.168.10.1
网络连通性测试应在两个方向进行:
- 开发板ping主机:在U-Boot或Linux系统下执行
ping 192.168.10.100 - 主机ping开发板:在主机终端执行
ping 192.168.10.50
注意:U-Boot阶段只能从开发板单向ping主机,这是正常现象。如果双向ping都不通,需要检查网络连接、防火墙设置和IP配置。
2.2 内核文件准备
内核映像和设备树文件需要放置在TFTP服务目录中,通常为/var/lib/tftpboot。关键操作步骤:
-
将编译好的zImage和.dtb文件复制到TFTP目录:
bash复制sudo cp arch/arm/boot/zImage /var/lib/tftpboot/ sudo cp arch/arm/boot/dts/imx6ull-alientek-emmc.dtb /var/lib/tftpboot/ -
设置文件权限:
bash复制sudo chmod 777 /var/lib/tftpboot/zImage /var/lib/tftpboot/imx6ull-alientek-emmc.dtb -
重启TFTP服务使配置生效:
bash复制sudo systemctl restart tftpd-hpa
2.3 文件系统准备
NFS共享的文件系统需要特别处理权限问题:
-
创建NFS共享目录结构:
bash复制mkdir -p ~/linux/nfs/rootfs -
解压BusyBox文件系统:
bash复制
tar xjf rootfs.tar.bz2 -C ~/linux/nfs/rootfs -
配置NFS共享:
编辑/etc/exports文件,添加:bash复制/home/duan/linux/nfs/rootfs *(rw,sync,no_root_squash,no_subtree_check) -
重启NFS服务:
bash复制sudo systemctl restart nfs-kernel-server
3. TFTP加载内核与设备树
3.1 U-Boot环境变量配置
在U-Boot命令行中设置网络参数和启动命令:
bash复制setenv ipaddr 192.168.10.50
setenv ethaddr 00:04:9f:04:d2:35
setenv gatewayip 192.168.10.1
setenv netmask 255.255.255.0
setenv serverip 192.168.10.100
saveenv
3.2 内核加载机制
bootcmd环境变量定义了启动时自动执行的命令序列:
bash复制setenv bootcmd 'tftp 80800000 zImage; tftp 83000000 imx6ull-alientek-emmc.dtb; bootz 80800000 - 83000000'
saveenv
这个命令序列完成了三个关键操作:
- 通过TFTP将zImage下载到内存地址0x80800000
- 通过TFTP将设备树文件下载到0x83000000
- 使用bootz命令启动内核
实际开发中,如果内核加载失败,可以尝试以下调试步骤:
- 确认TFTP服务正常运行:
sudo systemctl status tftpd-hpa- 检查文件权限:确保zImage和dtb文件有读权限
- 验证文件完整性:在主机上使用
file命令检查文件类型是否正确
4. NFS根文件系统挂载
4.1 bootargs参数详解
bootargs环境变量配置了内核启动参数,对于NFS根文件系统挂载尤为关键:
bash复制setenv bootargs 'console=ttymxc0,115200 root=/dev/nfs \
nfsroot=192.168.10.100:/home/duan/linux/nfs/rootfs,proto=tcp rw \
ip=192.168.10.50:192.168.10.100:192.168.10.1:255.255.255.0::eth0:off'
saveenv
参数解析:
console=ttymxc0,115200:指定控制台设备和波特率root=/dev/nfs:指定根文件系统通过NFS挂载nfsroot=...:NFS服务器地址和共享目录路径proto=tcp:使用TCP协议(更可靠)rw:以读写方式挂载ip=...:配置开发板网络参数
4.2 NFS挂载失败问题排查
当系统卡在"ALSA device list: No soundcards found"且无后续输出时,表明NFS挂载失败。常见原因及排查方法:
-
NFS共享配置错误
- 检查
/etc/exports文件是否正确 - 确认共享目录路径与bootargs中一致
- 验证权限设置(rw,sync,no_root_squash)
- 检查
-
目录权限问题
bash复制ls -ld /home/duan/linux/nfs/rootfs应有类似输出:
bash复制
drwxr-xr-x 18 root root 4096 Jun 1 10:00 /home/duan/linux/nfs/rootfs -
NFS服务未重启
bash复制sudo systemctl restart nfs-kernel-server -
协议版本不兼容(最常见问题)
老版本内核(如4.1.15)默认使用NFSv3,而高版本Ubuntu可能默认只支持NFSv4。
4.3 解决方案:强制使用NFSv3
修改bootargs,明确指定NFS版本:
bash复制setenv bootargs 'console=ttymxc0,115200 root=/dev/nfs \
nfsroot=192.168.10.100:/home/duan/linux/nfs/rootfs,proto=tcp,nfsvers=3 rw \
ip=192.168.10.50:192.168.10.100:192.168.10.1:255.255.255.0::eth0:off'
saveenv
关键修改是添加了nfsvers=3参数。此外,还可以在Ubuntu主机上配置NFS服务默认支持的版本:
-
编辑
/etc/default/nfs-kernel-server:bash复制sudo nano /etc/default/nfs-kernel-server -
修改或添加以下行:
bash复制RPCNFSDOPTS="--nfs-version 2,3,4 --debug --syslog" -
重启NFS服务:
bash复制sudo systemctl restart nfs-kernel-server
5. 完整测试流程
5.1 启动过程验证
-
设置好所有环境变量后,在U-Boot命令行执行:
bash复制
boot -
观察启动日志,成功标志包括:
- 内核正常解压和启动
- 成功挂载NFS根文件系统
- 出现登录提示符或初始化完成信息
-
成功启动后,可以验证文件系统:
bash复制ls / # 应显示根文件系统内容 touch /testfile # 测试写入权限
5.2 常见问题处理
-
NFS挂载超时
- 检查网络连接
- 确认NFS服务正在运行
- 验证防火墙设置(关闭或放行NFS端口)
-
权限被拒绝
- 确保
no_root_squash选项已启用 - 检查共享目录的所有者和权限
- 确保
-
文件系统损坏
- 重新解压文件系统
- 检查存储设备完整性
6. 开发效率优化技巧
6.1 自动化脚本
创建U-Boot脚本简化配置过程:
bash复制setenv load_kernel 'tftp 80800000 zImage'
setenv load_dtb 'tftp 83000000 imx6ull-alientek-emmc.dtb'
setenv boot_system 'bootz 80800000 - 83000000'
setenv net_config 'setenv ipaddr 192.168.10.50; setenv serverip 192.168.10.100'
setenv nfs_args 'setenv bootargs console=ttymxc0,115200 root=/dev/nfs nfsroot=192.168.10.100:/home/duan/linux/nfs/rootfs,proto=tcp,nfsvers=3 rw ip=192.168.10.50:192.168.10.100:192.168.10.1:255.255.255.0::eth0:off'
setenv bootcmd 'run net_config; run load_kernel; run load_dtb; run nfs_args; run boot_system'
saveenv
6.2 内核与文件系统更新流程
-
更新内核:
bash复制cp new_zImage /var/lib/tftpboot/zImage -
更新设备树:
bash复制cp new_dtb /var/lib/tftpboot/imx6ull-alientek-emmc.dtb -
更新文件系统:
bash复制
tar xjf new_rootfs.tar.bz2 -C ~/linux/nfs/rootfs -
重启开发板即可生效,无需其他操作
6.3 调试技巧
-
增加内核启动日志:
在bootargs中添加loglevel=8或debug参数 -
查看NFS连接状态:
在主机上执行:bash复制sudo cat /proc/fs/nfsd/portlist sudo rpcinfo -p -
网络抓包分析:
bash复制sudo tcpdump -i eth0 port 2049 or port 111 -w nfs.pcap
在实际开发中,这套网络加载方案可以显著提高开发效率。通过NFS挂载根文件系统,开发者可以直接在主机上修改代码,无需反复烧录即可在目标板上测试,特别适合驱动开发和应用程序调试阶段。