2. 开发环境搭建:交叉编译工具链安装、内核源码树获取与配置、QEMU模拟环境搭建
本章是进入网卡驱动实战开发前的“地基工程”。一个稳定、可复现的开发环境能让你在后续65讲中专注于驱动逻辑本身,而非被工具链或硬件问题打断。我们将依次完成三部分核心工作:交叉编译工具链(让主机编译出目标板可运行的二进制)、内核源码树(驱动编译与链接的依赖基础)、QEMU模拟环境(无需真实硬件即可运行和调试驱动)。
2.1 交叉编译工具链安装
网卡驱动最终运行在目标硬件(如ARM、RISC-V或MIPS架构)上,而开发通常在x86_64主机上进行。交叉编译工具链包含目标架构的编译器、链接器、库和调试器。
2.1.1 工具链选择与版本对照
| 目标架构 | 推荐工具链 | GCC版本 | glibc版本 | 适用场景 |
|---|---|---|---|---|
| ARM (32-bit) | arm-linux-gnueabihf- | ≥ 12.2 | ≥ 2.35 | 嵌入式网卡、IoT设备 |
| AArch64 (ARM64) | aarch64-linux-gnu- | ≥ 12.2 | ≥ 2.35 | 服务器网卡、智能网卡 |
| RISC-V (64-bit) | riscv64-linux-gnu- | ≥ 13.0 | ≥ 2.36 | 开源处理器网卡验证 |
aarch64-linux-gnu- 工具链为例。如果你使用其他架构,只需替换前缀即可,驱动代码本身与架构无关。
2.1.2 安装步骤(以Ubuntu 22.04主机为例)
- 安装标准工具链包
sudo apt update sudo apt install gcc-aarch64-linux-gnu binutils-aarch64-linux-gnu \ g++-aarch64-linux-gnu cpp-aarch64-linux-gnu - 验证安装
aarch64-linux-gnu-gcc --version # 输出应包含类似 "aarch64-linux-gnu-gcc (Ubuntu 12.2.0-3ubuntu1) 12.2.0" - 测试交叉编译
echo 'int main(){ return 0; }' > test.c aarch64-linux-gnu-gcc -static -o test test.c file test # 输出: test: ELF 64-bit LSB executable, ARM aarch64, ...
file 命令显示 x86-64 架构,说明你误用了本地 gcc。请检查是否完整输入了交叉编译器的全名,或使用 which aarch64-linux-gnu-gcc 确认路径。
2.2 内核源码树获取与配置
驱动模块的编译必须依赖内核源码树(Kernel Source Tree)中的头文件和编译规则。我们使用与目标运行环境一致的内核版本。
2.2.1 获取内核源码
推荐从 kernel.org 获取长期支持(LTS)版本,稳定性高且社区支持完善。
# 下载 Linux 6.1 LTS(本课程推荐版本)
wget https://cdn.kernel.org/pub/linux/kernel/v6.x/linux-6.1.76.tar.xz
tar -xf linux-6.1.76.tar.xz
cd linux-6.1.76
2.2.2 配置内核(为驱动编译做准备)
驱动模块编译需要内核源码树已生成 Module.symvers 和 include/config/auto.conf 等文件。我们执行一次最小配置即可。
# 生成默认配置(基于目标架构)
make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- defconfig
# 可选:启用额外的调试选项(便于驱动调试)
make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- menuconfig
# 在 Kernel hacking 中启用:
# [*] Debug Filesystem
# [*] Kernel debugging
# [*] Compile the kernel with debug info
.config— 内核配置选项,驱动编译时依赖其定义的宏。Module.symvers— 记录内核导出的符号CRC校验值,驱动模块必须与之匹配。include/generated/autoconf.h— 配置宏的头文件形式。
2.2.3 编译内核(可选,但推荐)
虽然驱动模块编译不要求完整编译内核,但编译一次内核可以验证工具链和配置的正确性,并生成后续QEMU启动所需的 Image 文件。
# 使用4个并行任务编译(根据CPU核心数调整)
make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- Image -j$(nproc)
# 编译设备树(QEMU启动需要)
make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- dtbs
# 编译内核模块(可选)
make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- modules
编译完成后,关键产出物位于:
arch/arm64/boot/Image— 内核镜像arch/arm64/boot/dts/qemu/— QEMU虚拟平台的设备树文件
2.3 QEMU模拟环境搭建
QEMU可以模拟完整的ARM64硬件平台,让我们在没有开发板的情况下运行和调试网卡驱动。本课程使用QEMU的 virt 平台,它提供了灵活的PCIe和网络设备支持。
2.3.1 安装QEMU
sudo apt install qemu-system-arm qemu-utils
2.3.2 创建根文件系统
内核启动后需要根文件系统(rootfs)来加载驱动模块和执行用户态程序。我们使用 Buildroot 快速生成最小根文件系统。
# 下载并配置Buildroot
wget https://buildroot.org/downloads/buildroot-2023.11.tar.xz
tar -xf buildroot-2023.11.tar.xz
cd buildroot-2023.11
# 配置为ARM64架构
make qemu_aarch64_virt_defconfig
make -j$(nproc)
生成的根文件系统镜像位于 output/images/rootfs.ext4。
2.3.3 启动QEMU并验证网络设备
使用以下命令启动QEMU,挂载内核镜像和根文件系统,并启用虚拟网卡。
qemu-system-aarch64 \
-machine virt \
-cpu cortex-a57 \
-smp 2 \
-m 1024 \
-kernel /path/to/linux-6.1.76/arch/arm64/boot/Image \
-drive file=/path/to/buildroot-2023.11/output/images/rootfs.ext4,format=raw,if=virtio \
-append "root=/dev/vda console=ttyAMA0" \
-netdev user,id=net0,hostfwd=tcp::2222-:22 \
-device virtio-net-pci,netdev=net0 \
-nographic
-netdev user— 用户模式网络,QEMU内部实现NAT,主机可通过localhost:2222SSH连接到虚拟机。-device virtio-net-pci— 添加一个PCIe接口的virtio网卡,这是我们后续驱动开发的目标设备。-nographic— 不使用图形窗口,所有输出重定向到终端。
启动后,在QEMU虚拟机内执行以下命令验证网络设备:
# 查看PCIe设备列表
lspci | grep Ethernet
# 查看网络接口
ip link show
# 测试网络连通性(QEMU默认网关为10.0.2.2)
ping -c 3 10.0.2.2
2.4 开发环境整体架构
下图展示了主机、交叉编译工具链、内核源码树和QEMU虚拟机之间的数据流与依赖关系。
2.5 环境验证清单
完成上述步骤后,使用下表逐项验证你的开发环境是否就绪。
| 验证项 | 验证命令 | 预期结果 |
|---|---|---|
| 交叉编译器可用 | aarch64-linux-gnu-gcc --version |
显示版本号,无“command not found” |
| 内核源码已配置 | ls linux-6.1.76/include/generated/autoconf.h |
文件存在且非空 |
| 内核镜像已编译 | ls linux-6.1.76/arch/arm64/boot/Image |
文件存在,大小约30-50MB |
| QEMU可启动 | 执行2.3.3节启动命令 | 虚拟机启动至登录提示符 |
| 网络设备可见 | 在QEMU内执行 ip link |
显示 eth0 或 enp0s1 接口 |
| 主机-QEMU通信 | 在QEMU内 ping 10.0.2.2 |
收到ICMP回复 |
net_device 的初始化与注册。请确保本章所有验证项均通过,后续实验将直接依赖此环境。