3. Bootloader移植与配置
做嵌入式Linux开发,第一步不是写代码,而是先把“窝”搭好。我见过不少新手,代码写得挺溜,结果卡在环境配置上好几天,最后发现是工具链版本不对。这一章,咱们就把开发环境彻底理清楚。
说白了,我们的目标就三个:一台能跑Linux的虚拟机、一套能把代码编译成ARM架构可执行文件的工具链、以及能让开发板和宿主机无障碍传文件的服务。这三样齐了,后面的事情才谈得上。
3.1 Ubuntu虚拟机安装——选对版本,少走弯路
虚拟机软件我推荐 VMware Workstation Pro 或者 VirtualBox,两者我都用过。个人习惯用 VMware,网络配置更直观一些。但 VirtualBox 免费,学生党用着也没压力。
版本选择: 别追新。Ubuntu 22.04 虽然新,但有些老牌工具链的依赖包还没完全适配。我建议用 Ubuntu 20.04 LTS,稳定、资料多、遇到问题随便一搜就有答案。
安装步骤其实很简单,我快速过一下重点:
- 下载镜像: 去 Ubuntu 官网下载 20.04.6 LTS 桌面版 ISO。
- 新建虚拟机: 选择“典型”安装,稍后安装操作系统,选 Linux → Ubuntu 64 位。
- 网络类型: 选“桥接模式”。这样虚拟机跟开发板就在同一个网段,TFTP/NFS 才能通。
- 安装系统: 挂载 ISO,启动虚拟机,一路默认就行。分区我建议手动分——
/给 30GB,/home给剩下的,swap 给 4GB。
3.2 交叉编译工具链配置——arm-linux-gnueabihf
交叉编译,说白了就是在 x86 的电脑上编译出 ARM 能跑的程序。你想想看,开发板那点算力,编译个 Linux 内核得等到猴年马月?所以这事必须在宿主机上干。
工具链的选择,我推荐 Linaro 提供的 arm-linux-gnueabihf- 版本。为什么是它?因为它是 ARM 官方推荐的,更新及时,而且支持硬浮点(hf),性能比软浮点好不少。
3.2.1 下载与安装
# 下载 Linaro 工具链(以 gcc-linaro-7.5.0 为例)
wget https://releases.linaro.org/components/toolchain/binaries/7.5-2019.12/arm-linux-gnueabihf/gcc-linaro-7.5.0-2019.12-x86_64_arm-linux-gnueabihf.tar.xz
# 解压到 /opt 目录
sudo tar -xvf gcc-linaro-7.5.0-2019.12-x86_64_arm-linux-gnueabihf.tar.xz -C /opt/
# 重命名(方便管理)
sudo mv /opt/gcc-linaro-7.5.0-2019.12-x86_64_arm-linux-gnueabihf /opt/gcc-arm-linux-gnueabihf
3.2.2 配置环境变量
我个人习惯把工具链路径加到 ~/.bashrc 里,这样每次打开终端自动生效:
# 编辑 ~/.bashrc
vim ~/.bashrc
# 在文件末尾添加
export PATH=$PATH:/opt/gcc-arm-linux-gnueabihf/bin
export CROSS_COMPILE=arm-linux-gnueabihf-
export ARCH=arm
# 使配置生效
source ~/.bashrc
3.2.3 验证安装
# 查看编译器版本
arm-linux-gnueabihf-gcc --version
# 编译一个测试程序
echo 'int main(){ return 0; }' > test.c
arm-linux-gnueabihf-gcc -o test test.c
# 查看生成的文件类型
file test
# 输出应为:ELF 32-bit LSB executable, ARM, EABI5 version 1 (SYSV)
file test 显示的是 x86-64,说明你用的是宿主机自带的 gcc,不是交叉编译器。检查一下 PATH 顺序,或者直接用绝对路径调用。
3.3 TFTP服务搭建——给开发板传文件
TFTP 这东西,说白了就是一个极简版的 FTP,没有认证、没有目录列表,但胜在轻量。U-Boot 里默认就支持 TFTP 下载,所以我们用它来给开发板传内核镜像和设备树。
3.3.1 安装与配置
# 安装 TFTP 服务端和客户端
sudo apt-get update
sudo apt-get install tftpd-hpa tftp-hpa
# 创建 TFTP 根目录
sudo mkdir -p /tftpboot
sudo chmod 777 /tftpboot
# 修改配置文件
sudo vim /etc/default/tftpd-hpa
配置文件内容如下:
TFTP_USERNAME="tftp"
TFTP_DIRECTORY="/tftpboot"
TFTP_ADDRESS="0.0.0.0:69"
TFTP_OPTIONS="-l -c -s"
-c 选项允许上传文件,调试时很有用。但生产环境建议去掉,只保留 -l -s。
3.3.2 启动与测试
# 重启服务
sudo systemctl restart tftpd-hpa
sudo systemctl enable tftpd-hpa
# 本地测试
echo "Hello TFTP" > /tftpboot/test.txt
tftp localhost
tftp> get test.txt
tftp> quit
cat test.txt # 应该看到 "Hello TFTP"
3.4 NFS服务搭建——共享根文件系统
NFS 比 TFTP 高级多了。它能让开发板直接把宿主机上的一个目录挂载成自己的根文件系统。调试驱动时,你改完代码、编译完,开发板重启就能用上新程序,不用反复烧写 Flash。
3.4.1 安装与配置
# 安装 NFS 服务端
sudo apt-get install nfs-kernel-server
# 创建共享目录
sudo mkdir -p /srv/nfs/rootfs
sudo chmod 777 /srv/nfs/rootfs
# 编辑导出配置文件
sudo vim /etc/exports
在 /etc/exports 中添加:
/srv/nfs/rootfs *(rw,sync,no_subtree_check,no_root_squash)
no_root_squash 这个选项很关键。不加的话,开发板上的 root 用户会被映射成 nobody,很多操作会权限不足。我曾经调试一个驱动,死活加载不了,最后发现是 NFS 权限问题。
3.4.2 启动与验证
# 导出共享目录
sudo exportfs -a
# 重启 NFS 服务
sudo systemctl restart nfs-kernel-server
# 查看导出列表
showmount -e localhost
# 本地挂载测试
sudo mount -t nfs localhost:/srv/nfs/rootfs /mnt
ls /mnt # 应该能看到内容
sudo umount /mnt
3.5 开发板端配置——U-Boot 启动参数
服务端搭好了,开发板也得配合。在 U-Boot 命令行里设置好环境变量,才能让 TFTP 和 NFS 跑起来。
| 环境变量 | 说明 | 示例值 |
|---|---|---|
serverip |
宿主机的 IP 地址 | 192.168.1.100 |
ipaddr |
开发板的 IP 地址 | 192.168.1.200 |
netmask |
子网掩码 | 255.255.255.0 |
gateway |
网关 | 192.168.1.1 |
bootcmd |
自动启动命令 | 见下方示例 |
一个典型的 NFS 启动参数设置:
setenv serverip 192.168.1.100
setenv ipaddr 192.168.1.200
setenv netmask 255.255.255.0
setenv gateway 192.168.1.1
# 从 TFTP 下载内核和设备树
setenv bootcmd 'tftp 0x42000000 zImage; tftp 0x43000000 imx6ull.dtb; bootz 0x42000000 - 0x43000000'
# NFS 根文件系统
setenv bootargs 'console=ttymxc0,115200 root=/dev/nfs nfsroot=192.168.1.100:/srv/nfs/rootfs,proto=tcp rw ip=192.168.1.200'
saveenv
boot
bootcmd 里让它自动跑。
3.6 常见问题与避坑指南
- TFTP 超时: 检查防火墙。Ubuntu 默认开了 ufw,关掉或者放行 UDP 69 端口。
sudo ufw disable或者sudo ufw allow 69/udp。 - NFS 挂载失败: 检查
/etc/exports语法,每行结尾不能有空格。用exportfs -v查看实际导出的路径和权限。 - 交叉编译器报错 "No such file or directory": 大概率是 64 位系统缺少 32 位库。安装
sudo apt-get install lib32z1 lib32ncurses5试试。 - 开发板 ping 不通宿主机: 检查网线、交换机,确认桥接模式。在虚拟机里
ifconfig看看 IP 是不是跟开发板在同一网段。
好了,环境搭到这步,你的开发“窝”就算建好了。后面写驱动、编译内核、调试应用,全都要依赖这套环境。别嫌麻烦,一次配好,后面省心。