1. Linux内核开发环境搭建
嵌入式Linux内核驱动开发的第一步,是构建一个稳定、可复现的开发环境。本章将指导你从零开始搭建虚拟机、配置内核源码树、安装交叉编译工具链,并建立NFS与TFTP调试环境。这套环境将贯穿整个课程,支撑后续所有驱动实验。
环境概览:主机使用Windows/macOS,虚拟机运行Ubuntu 22.04 LTS作为开发工作站,目标板为ARM Cortex-A系列(如QEMU模拟的vexpress-a9或真实开发板)。所有工具链和调试服务均部署在虚拟机中。
1.1 虚拟机安装Ubuntu
推荐使用VMware Workstation Pro 17+或VirtualBox 7+。以下步骤以VMware为例:
- 下载Ubuntu Server 22.04 LTS ISO(建议使用Server版,减少桌面环境资源占用)。
- 创建虚拟机:分配4核CPU、8GB内存、80GB磁盘(动态扩展)。
- 网络配置:使用桥接模式,确保虚拟机与主机在同一网段,便于后续NFS/TFTP通信。
- 安装系统:选择最小化安装,仅安装OpenSSH Server和标准系统工具。
- 更新与基础包:
sudo apt update && sudo apt upgrade -y
sudo apt install -y build-essential git vim net-tools nfs-kernel-server tftpd-hpa
关键配置:固定虚拟机IP地址(例如192.168.1.100),避免每次重启后IP变化导致调试中断。编辑
/etc/netplan/00-installer-config.yaml 设置静态IP。
1.2 配置内核源码树
内核源码树是驱动开发的核心依赖。你需要下载与目标板匹配的内核版本,并完成首次编译。
| 步骤 | 命令/操作 | 说明 |
|---|---|---|
| 1. 下载内核 | wget https://cdn.kernel.org/pub/linux/kernel/v6.x/linux-6.1.80.tar.xz |
选择LTS版本,稳定性优先 |
| 2. 解压 | tar -xf linux-6.1.80.tar.xz -C ~/ |
解压到用户目录 |
| 3. 配置内核 | make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- vexpress_defconfig |
使用vexpress默认配置 |
| 4. 编译内核 | make -j$(nproc) ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- zImage |
生成压缩内核镜像 |
| 5. 编译设备树 | make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- dtbs |
生成.dtb文件 |
| 6. 编译模块 | make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- modules |
编译内核模块 |
常见错误:如果编译时提示缺少ncurses库,执行
sudo apt install libncurses-dev。如果使用menuconfig图形配置,需要安装 libncurses5-dev。
1.3 安装交叉编译工具链
交叉编译工具链允许你在x86主机上编译出ARM架构的可执行文件。推荐使用Linaro提供的GCC工具链。
# 下载ARM GCC工具链
wget https://releases.linaro.org/components/toolchain/binaries/latest-7/arm-linux-gnueabihf/gcc-linaro-7.5.0-2019.12-x86_64_arm-linux-gnueabihf.tar.xz
# 解压到/opt
sudo tar -xf gcc-linaro-7.5.0-2019.12-x86_64_arm-linux-gnueabihf.tar.xz -C /opt/
# 添加环境变量
echo 'export PATH=$PATH:/opt/gcc-linaro-7.5.0-2019.12-x86_64_arm-linux-gnueabihf/bin' >> ~/.bashrc
source ~/.bashrc
# 验证安装
arm-linux-gnueabihf-gcc --version
| 工具链组件 | 用途 | 示例命令 |
|---|---|---|
| arm-linux-gnueabihf-gcc | C语言交叉编译器 | 编译内核、驱动、应用程序 |
| arm-linux-gnueabihf-ld | 链接器 | 链接目标文件生成可执行文件 |
| arm-linux-gnueabihf-objdump | 反汇编工具 | 查看二进制文件指令 |
| arm-linux-gnueabihf-objcopy | 格式转换工具 | ELF转二进制/十六进制 |
选择建议:对于Linux 6.x内核,推荐使用GCC 10+工具链。如果目标板是Cortex-A7/A15,使用
arm-linux-gnueabihf- 前缀;如果是Cortex-A53/A72(64位),使用 aarch64-linux-gnu- 前缀。
1.4 搭建NFS与TFTP调试环境
NFS(网络文件系统)允许目标板挂载虚拟机的文件系统,实现内核模块的热替换调试。TFTP(简单文件传输协议)用于快速下载内核镜像和设备树到目标板。
1.4.1 NFS服务配置
# 安装NFS服务器
sudo apt install nfs-kernel-server
# 创建共享目录
sudo mkdir -p /srv/nfs/rootfs
sudo chown nobody:nogroup /srv/nfs/rootfs
sudo chmod 777 /srv/nfs/rootfs
# 配置导出文件
echo "/srv/nfs/rootfs *(rw,sync,no_subtree_check,no_root_squash)" | sudo tee -a /etc/exports
# 重启服务
sudo systemctl restart nfs-kernel-server
sudo exportfs -a
1.4.2 TFTP服务配置
# 安装TFTP服务器
sudo apt install tftpd-hpa
# 配置TFTP目录
sudo mkdir -p /srv/tftp
sudo chmod 777 /srv/tftp
# 修改配置文件 /etc/default/tftpd-hpa
# 内容如下:
# TFTP_USERNAME="tftp"
# TFTP_DIRECTORY="/srv/tftp"
# TFTP_ADDRESS="0.0.0.0:69"
# TFTP_OPTIONS="--secure --create"
# 重启服务
sudo systemctl restart tftpd-hpa
1.4.3 目标板启动参数配置
在U-Boot中设置以下环境变量,实现从NFS启动:
setenv ipaddr 192.168.1.101
setenv serverip 192.168.1.100
setenv netmask 255.255.255.0
setenv gatewayip 192.168.1.1
# 通过TFTP下载内核和设备树
setenv bootcmd 'tftp 0x60000000 zImage; tftp 0x65000000 vexpress-v2p-ca9.dtb; bootz 0x60000000 - 0x65000000'
# 通过NFS挂载根文件系统
setenv bootargs 'console=ttyAMA0,115200 root=/dev/nfs nfsroot=192.168.1.100:/srv/nfs/rootfs rw ip=192.168.1.101'
saveenv
boot
调试效率提升:将编译好的内核模块(.ko文件)直接复制到NFS共享目录的对应路径下,目标板启动后即可通过
insmod / rmmod 动态加载/卸载驱动,无需重启系统。这是驱动开发中最常用的调试循环。
1.5 环境验证清单
完成上述配置后,使用以下清单验证环境是否就绪:
| 验证项 | 验证方法 | 预期结果 |
|---|---|---|
| 虚拟机网络 | ping 192.168.1.1 |
能够ping通网关 |
| 交叉编译工具链 | arm-linux-gnueabihf-gcc --version |
显示版本信息 |
| 内核编译 | ls -lh arch/arm/boot/zImage |
文件存在且大小正常 |
| NFS服务 | showmount -e localhost |
显示共享目录列表 |
| TFTP服务 | tftp localhost -c get test.txt |
成功下载文件 |
| 目标板启动 | 串口输出日志 | 内核启动完成,进入shell |
防火墙注意:如果目标板无法连接NFS/TFTP,检查虚拟机防火墙是否放行相关端口:NFS使用2049端口,TFTP使用69端口(UDP)。执行
sudo ufw allow 2049 和 sudo ufw allow 69/udp。