1. 项目概述:为什么选择网络启动?
拿到一块像NXP FRWY-LS1046A这样的高性能开发板,第一件事往往就是给它“装系统”。传统的方式是把系统镜像烧录到板载的eMMC或SD卡里,这很直接,但效率不高。尤其是在开发调试阶段,你可能需要频繁地更换内核、修改根文件系统,每次都要重新烧录,不仅耗时,还增加了存储介质的磨损。
网络启动,或者说PXE启动,就是为了解决这个痛点而生的。它的核心思想是“计算与存储分离”:开发板本身不需要存储完整的系统,只需要一个极小的引导程序(U-Boot)能从网络获取启动所需的一切——内核、设备树、根文件系统。对于FRWY-LS1046A这块基于Layerscape架构、拥有四个Cortex-A72核心的板子来说,网络启动能极大提升开发迭代速度。想象一下,你在服务器上编译好一个新内核,开发板重启就能直接加载测试,整个过程无需插拔任何存储卡,这才是高效的嵌入式Linux开发流程。
这个配置过程,本质上是搭建一个微型的、为开发板服务的网络启动服务器环境,并正确配置开发板的固件,让两者能“握手”成功。下面,我就以Ubuntu 20.04 LTS作为服务器系统,带你一步步走通FRWY-LS1046A网络启动的全流程。
2. 核心组件与网络拓扑设计
在动手配置之前,我们需要搞清楚网络启动链条上的几个关键角色和它们之间的协作关系。这就像一场接力赛,每个环节都不能掉链子。
2.1 网络启动链条解析
- 开发板U-Boot :第一棒选手。它存储在板载的QSPI Flash或SD卡中。上电后,U-Boot初始化网络接口(通常是某个FMAN端口),然后向网络发送DHCP请求。
-
DHCP服务器
:第二棒,也是指挥中心。它响应开发板的请求,不仅分配IP地址,更重要的是通过
dhcpd.conf中的next-server和filename选项,告诉U-Boot:TFTP服务器的地址是什么,以及要下载的引导文件(如uImage或fitImage)叫什么名字。 -
TFTP服务器
:第三棒,物资仓库。这是一个简单的文件传输协议服务器。U-Boot在拿到DHCP提供的信息后,会向指定的TFTP服务器请求下载引导文件、设备树(
fsl-ls1046a-frwy.dtb)以及可能用到的RAMDisk镜像。 - NFS服务器 :最后一棒,提供完整的运行环境。内核启动后,需要挂载根文件系统(rootfs)。我们这里配置为通过NFS挂载服务器上的一个目录。这样,根文件系统的所有修改都在服务器端,开发板运行时直接使用。
2.2 网络环境规划
一个清晰稳定的网络环境是成功的基础。我强烈建议你采用以下拓扑,可以避免很多不必要的麻烦:
[ 开发板 FRWY-LS1046A ] <--直连网线--> [ 宿主机/服务器 ]
(eth0, 例如 192.168.1.100) (eth0, 例如 192.168.1.1)
|
| (运行 DHCP, TFTP, NFS 服务)
V
[ 服务配置完成 ]
注意 :将开发板与服务器用一根网线直接连接,并配置一个独立的私有网段(如
192.168.1.0/24)。不要将它们接入你日常办公的复杂局域网。这样可以避免DHCP请求被其他路由器响应,导致U-Boot获取到错误的引导信息,同时也更安全、更稳定。
2.3 服务器端组件安装清单
在开始配置前,请确保你的Ubuntu服务器已安装以下软件包:
sudo apt update
sudo apt install isc-dhcp-server tftpd-hpa nfs-kernel-server net-tools
-
isc-dhcp-server:我们将使用它提供DHCP服务。 -
tftpd-hpa:这是一个功能简单、易于配置的TFTP服务器。 -
nfs-kernel-server:用于导出NFS共享目录。 -
net-tools:包含ifconfig等网络工具,便于查看和配置网络。
3. 服务器端服务配置详解
服务配置是核心,每一步都需要仔细核对。我们按照依赖顺序来配置:先固定服务器IP,再配置DHCP,接着是TFTP,最后是NFS。
3.1 配置服务器静态IP地址
由于我们是直连,需要手动给服务器的网口设置一个静态IP。
-
查看网口名称:
ip addr。假设我们使用的网口是enp3s0。 -
编辑Netplan配置文件(Ubuntu 18.04+使用Netplan):
sudo nano /etc/netplan/01-netcfg.yaml -
写入以下配置(根据你的网口名称修改):
network: version: 2 renderer: networkd ethernets: enp3s0: # 替换为你的实际网口名 addresses: - 192.168.1.1/24 dhcp4: no optional: true -
应用配置:
sudo netplan apply。然后使用ip addr show enp3s0确认IP已设置为192.168.1.1。
3.2 配置DHCP服务器 (isc-dhcp-server)
DHCP服务器的配置是关键,它决定了U-Boot能否找到正确的引导路径。
-
编辑主配置文件:
sudo nano /etc/dhcp/dhcpd.conf -
在文件末尾添加以下配置块。请特别注意
hardware ethernet这一行,你需要将它替换为你开发板网口的实际MAC地址。你可以在U-Boot命令行中使用env print ethaddr命令查看,或者查看板子上的标签。# 为LS1046A FRWY开发板配置的DHCP子网 subnet 192.168.1.0 netmask 255.255.255.0 { range 192.168.1.50 192.168.1.150; # 为其他设备预留的地址池,开发板用固定IP option routers 192.168.1.1; option subnet-mask 255.255.255.0; option domain-name-servers 8.8.8.8; # 可选的DNS服务器 # 为特定MAC地址的开发板分配固定IP并指定启动文件 host ls1046a-frwy { hardware ethernet 00:04:9f:xx:xx:xx; # !!!必须替换为你的开发板MAC地址!!! fixed-address 192.168.1.100; # 为开发板分配的固定IP filename "uImage"; # 告诉U-Boot从TFTP下载的文件名 next-server 192.168.1.1; # 告诉U-Boot TFTP服务器的地址(即本机) } }实操心得 :使用
fixed-address为开发板分配固定IP非常有用。这样,无论服务器重启还是开发板重启,你都知道开发板的IP是192.168.1.100,后续通过NFS挂载或ssh连接都会非常方便。next-server必须指向你的服务器IP。 -
指定DHCP服务监听的网卡。编辑:
sudo nano /etc/default/isc-dhcp-server修改
INTERFACESv4的值为你连接开发板的网口名:INTERFACESv4="enp3s0" -
启动并启用DHCP服务:
sudo systemctl restart isc-dhcp-server sudo systemctl enable isc-dhcp-server -
检查服务状态:
sudo systemctl status isc-dhcp-server。确保状态为active (running)。可以用sudo journalctl -u isc-dhcp-server -f实时查看日志,待会儿开发板启动时就能看到DHCP请求记录。
3.3 配置TFTP服务器 (tftpd-hpa)
TFTP服务器用于存放U-Boot需要下载的二进制文件。
-
编辑TFTP配置文件:
sudo nano /etc/default/tftpd-hpa -
确保配置如下。
TFTP_DIRECTORY是TFTP服务的根目录,所有启动文件都要放在这里。TFTP_USERNAME="tftp" TFTP_DIRECTORY="/var/lib/tftpboot" # TFTP根目录 TFTP_ADDRESS=":69" TFTP_OPTIONS="--secure --ipv4" -
创建TFTP目录并设置权限(如果不存在):
sudo mkdir -p /var/lib/tftpboot sudo chown -R tftp:tftp /var/lib/tftpboot sudo chmod -R 755 /var/lib/tftpboot -
将你的启动文件复制到TFTP目录。至少需要:
-
uImage:Linux内核镜像(使用mkimage工具封装过的)。 -
fsl-ls1046a-frwy.dtb:针对FRWY开发板的设备树二进制文件。 例如:
cp /path/to/your/linux/uImage /var/lib/tftpboot/ cp /path/to/your/linux/fsl-ls1046a-frwy.dtb /var/lib/tftpboot/ -
-
重启TFTP服务:
sudo systemctl restart tftpd-hpa sudo systemctl enable tftpd-hpa -
本地测试TFTP服务是否正常(从服务器自己下载):
如果成功下载,说明TFTP服务基础功能正常。cd /tmp tftp 192.168.1.1 -c get uImage
3.4 配置NFS服务器
NFS服务器用于共享根文件系统。
-
创建你要共享的根文件系统目录,并放入完整的根文件系统内容(可以从SD卡镜像中提取,或使用yocto/buildroot构建)。
sudo mkdir -p /nfsroot/rootfs_ls1046a # 假设你的根文件系统在 /home/user/rootfs 目录下 sudo cp -a /home/user/rootfs/* /nfsroot/rootfs_ls1046a/ -
编辑NFS导出配置文件:
sudo nano /etc/exports -
添加以下一行,允许开发板IP地址访问该目录,并赋予必要的权限(
rw读写,sync同步写入,no_subtree_check不检查子目录,no_root_squash允许root用户保持权限,这对开发板很重要)。/nfsroot/rootfs_ls1046a 192.168.1.100(rw,sync,no_subtree_check,no_root_squash)重要警告 :
no_root_squash选项在开发环境中很方便,但它意味着开发板上的root用户对服务器共享目录拥有完全权限。 请确保此NFS共享仅在你的安全内网中使用,切勿在公共网络环境下如此配置。 -
使NFS导出配置生效:
sudo exportfs -ra -
重启NFS服务(或使其重新加载配置):
sudo systemctl restart nfs-kernel-server -
验证导出是否成功:
sudo showmount -e localhost。你应该能看到/nfsroot/rootfs_ls1046a被导出给了192.168.1.100。
4. 开发板U-Boot环境配置
服务器端准备就绪后,接下来需要配置开发板的U-Boot,告诉它如何从网络启动。
4.1 进入U-Boot命令行
给开发板上电,在串口终端显示
Hit any key to stop autoboot
时,快速按下任意键(如空格),即可进入U-Boot命令行。提示符通常为
=>
。
4.2 设置U-Boot环境变量
我们需要设置一系列环境变量来定义启动流程。在U-Boot命令行中逐条输入以下命令。
请根据你的实际情况修改服务器IP(
serverip
)、开发板IP(
ipaddr
)、文件路径和名称。
# 设置开发板自身的IP地址(与DHCP分配的固定IP一致)
setenv ipaddr 192.168.1.100
# 设置服务器的IP地址
setenv serverip 192.168.1.1
# 设置网络掩码
setenv netmask 255.255.255.0
# 设置网关(通常就是服务器IP)
setenv gatewayip 192.168.1.1
# 设置从TFTP加载的内核镜像文件名
setenv image_name uImage
# 设置设备树文件名
setenv fdt_file fsl-ls1046a-frwy.dtb
# 定义网络加载内核的命令
setenv netload_kernel 'tftp ${loadaddr} ${image_name}; tftp ${fdtaddr} ${fdt_file}'
# 定义NFS根文件系统的路径。注意:服务器IP后是冒号,路径是服务器上的绝对路径。
setenv nfsroot /nfsroot/rootfs_ls1046a
# 定义内核启动参数。这是最关键的一行:
# console=ttyS0,115200: 指定串口控制台。
# root=/dev/nfs: 指定根文件系统类型为NFS。
# nfsroot=${serverip}:${nfsroot}: 指定NFS服务器的IP和路径。
# ip=${ipaddr}:${serverip}::${netmask}::eth0:off: 手动配置网络参数,避免内核再次DHCP。
# rw: 以读写方式挂载根文件系统。
setenv bootargs console=ttyS0,115200 root=/dev/nfs nfsroot=${serverip}:${nfsroot} ip=${ipaddr}:${serverip}::${netmask}::eth0:off rw
# 定义完整的网络启动命令
setenv netboot 'run netload_kernel; bootm ${loadaddr} - ${fdtaddr}'
# 将启动命令保存到 bootcmd,这样下次上电会自动执行网络启动
setenv bootcmd 'run netboot'
# 保存所有环境变量到持久化存储(如QSPI Flash)
saveenv
4.3 环境变量解析与避坑指南
-
loadaddr和fdtaddr:这是U-Boot预定义的内存加载地址(通常是0x82000000和0x90000000左右),用于临时存放从网络下载的内核和设备树。一般无需修改,除非有地址冲突。 -
bootargs:这是传递给Linux内核的命令行参数。ip=参数的格式非常关键,错误的格式会导致内核无法配置网络,进而NFS挂载失败。格式为:ip=<客户端IP>:<服务器IP>:<网关IP>:<子网掩码>:<主机名>:<网卡>:<自动配置>。我们这里网关和服务器是同一台,所以网关处留空,用::表示。 -
常见错误
:
nfsroot路径错误。服务器路径必须是/etc/exports中定义的绝对路径。如果遇到mount.nfs: access denied by server错误,首先检查/etc/exports的配置和权限,以及no_root_squash选项。
5. 执行网络启动与验证
配置完成后,就可以进行首次网络启动了。
-
在U-Boot命令行中,直接执行我们定义的启动命令:
run netboot或者,因为我们已经将
bootcmd设置为run netboot,你也可以直接输入boot命令,或者重启开发板(输入reset)让它自动启动。 -
观察启动日志 :
- U-Boot会首先通过DHCP获取IP(如果你设置了固定IP,这一步很快)。
-
接着,你会看到
Using eth0 device和TFTP from server...的信息,表示正在从服务器下载uImage和.dtb文件。注意观察是否有Loading:和Bytes transferred =的成功提示。 - 下载完成后,U-Boot会跳转到内核入口点,开始启动Linux内核。
-
内核启动过程中,最关键的一行是:
VFS: Mounted root (nfs filesystem) on device 0:14.。这表示内核成功挂载了NFS根文件系统。 -
如果一切顺利,最后你会看到根文件系统的登录提示符(如
ls1046afrwy:~#)。
-
登录与验证 :
- 通过串口登录开发板。
-
执行
ifconfig或ip addr命令,确认网卡(如eth0)的IP地址是192.168.1.100。 -
执行
mount | grep nfs,确认根文件系统/的类型是nfs,并且显示了正确的服务器路径。 -
尝试在开发板的
/目录下创建一个测试文件,然后到服务器的/nfsroot/rootfs_ls1046a目录下查看,应该能看到该文件。这验证了NFS读写功能正常。
6. 常见问题排查与调试技巧实录
即使按照步骤操作,也可能会遇到问题。这里记录了几个我踩过的坑和解决方法。
6.1 DHCP服务未响应
-
现象
:U-Boot卡在
Waiting for PHY auto negotiation to complete...之后,没有获取到IP,或者提示DHCP failed。 -
排查
:
- 检查物理连接 :网线是否插好?服务器和开发板的网口指示灯是否亮起?
-
检查服务器IP配置
:在服务器上执行
ip addr,确认连接开发板的网口IP是192.168.1.1。 -
检查DHCP服务状态
:
sudo systemctl status isc-dhcp-server。查看是否有错误。 -
查看DHCP日志
:
sudo journalctl -u isc-dhcp-server -f。重启开发板,看是否有来自开发板MAC地址的DHCP请求DHCPDISCOVER,以及服务器是否发出了DHCPOFFER。 -
检查防火墙
:Ubuntu可能默认开启了
ufw防火墙。执行sudo ufw status。如果是active,需要开放DHCP(67/udp)和TFTP(69/udp)端口:sudo ufw allow 67/udp,sudo ufw allow 69/udp,或者直接关闭防火墙进行测试:sudo ufw disable。
6.2 TFTP传输失败或超时
-
现象
:U-Boot提示
TFTP error: 'File not found' (1)或TFTP timeout。 -
排查
:
-
检查文件路径和权限
:确保
uImage等文件在/var/lib/tftpboot/目录下,并且权限是可读的(ls -l /var/lib/tftpboot/)。 -
测试TFTP服务
:在服务器本机用
tftp客户端自测(如前文所述)。 -
检查文件名大小写
:U-Boot环境变量
image_name和实际文件名必须完全一致,Linux区分大小写。 -
检查TFTP目录权限
:TFTP守护进程通常以
tftp用户运行。确保/var/lib/tftpboot目录及其下的文件对tftp用户或所有用户至少有读权限。可以尝试sudo chmod -R 755 /var/lib/tftpboot。 -
使用绝对路径
:在U-Boot的
tftp命令中,文件名是相对于TFTP根目录的。不要包含路径。
-
检查文件路径和权限
:确保
6.3 内核启动后NFS挂载失败
-
现象
:内核启动后卡住,最后报错
Kernel panic - not syncing: VFS: Unable to mount root fs on unknown-block(0,0)或mount.nfs: access denied by server。 -
排查
:
-
检查NFS导出配置
:确保
/etc/exports中配置的客户端IP是开发板的IP(192.168.1.100),并且路径正确。执行sudo exportfs -v可以查看详细的导出信息。 -
检查NFS服务状态
:
sudo systemctl status nfs-kernel-server。 -
检查内核启动参数
bootargs:这是最常见的问题源。仔细核对nfsroot=后面的服务器IP和路径,以及ip=参数的格式。可以在U-Boot中使用printenv bootargs查看,在内核启动时也会打印出来。 -
在服务器上测试NFS挂载
:在服务器上自己挂载自己的共享,可以排除NFS服务本身的问题。
如果挂载失败,根据错误信息排查sudo mkdir -p /mnt/test_nfs sudo mount -t nfs 192.168.1.1:/nfsroot/rootfs_ls1046a /mnt/test_nfs/etc/exports和权限。成功后sudo umount /mnt/test_nfs。 -
检查开发板与服务器的网络连通性
:在内核启动后(如果还没panic),可以尝试按
Ctrl+C打断启动,进入内核的初始化内存磁盘(initrd)命令行(如果内核编译了该功能)。然后尝试ping 192.168.1.1。如果不通,说明内核的网络配置(ip=参数)可能有问题。
-
检查NFS导出配置
:确保
6.4 从网络启动切换回本地启动
如果你需要临时从SD卡或eMMC启动,可以在U-Boot命令行中修改
bootcmd
并保存。
-
例如,切换回SD卡启动(假设SD卡上有系统):
setenv bootcmd 'mmc dev 0; ext4load mmc 0:1 ${loadaddr} /boot/uImage; ext4load mmc 0:1 ${fdtaddr} /boot/fsl-ls1046a-frwy.dtb; bootm ${loadaddr} - ${fdtaddr}' saveenv reset -
要恢复网络启动,只需重新设置
bootcmd为run netboot并保存即可。这种灵活性是开发板的巨大优势。
整个配置过程看似步骤繁多,但一旦跑通,你就会发现它在嵌入式Linux开发中带来的效率提升是巨大的。所有的编译、修改都在服务器端完成,开发板只是一个纯粹的“计算终端”,重启即更新。对于驱动调试、应用测试等需要频繁变更系统组件的场景,网络启动几乎是必备的利器。



1494

被折叠的 条评论
为什么被折叠?



