2、开发环境搭建:内核源码树准备、交叉编译工具链配置、QEMU/KVM虚拟化测试环境搭建
好,咱们正式开始动手。这一章我带你把开发环境搭起来。说实话,很多初学者把精力都花在写代码上,结果环境没配好,编译通不过,调试跑不起来,白白浪费大量时间。我个人习惯是,先把环境搞利索了,后面才能专心搞驱动。
这一章我们做三件事:准备内核源码树、配置交叉编译工具链、搭建QEMU/KVM虚拟化测试环境。这三样东西,说白了就是你开发网卡驱动的“三件套”。
2.1 内核源码树准备
驱动开发离不开内核源码。你想想看,驱动是要嵌入到内核里运行的,你不看内核的接口、数据结构,怎么写?
为什么要准备内核源码树?
因为网卡驱动本质上是一个内核模块。它要调用内核提供的API,比如网络协议栈的接口、PCIe子系统的函数、内存管理的函数。这些API的声明和实现都在内核源码里。没有源码树,你连头文件都找不到,更别说编译了。
我建议你这样做:
- 下载内核源码:去
kernel.org下载长期支持版本(LTS)。我个人推荐 5.10.x 或 6.1.x,这两个版本稳定,社区支持好,而且Intel网卡驱动在这两个版本上表现都不错。 - 解压到固定目录:比如
/home/user/linux-5.10.210。别放桌面或下载目录,路径里别有中文和空格。 - 配置内核:不需要完整编译内核,但至少要生成
.config文件。运行make defconfig生成默认配置,然后make menuconfig可以微调。 - 编译内核模块依赖:运行
make modules_prepare。这一步会生成一些必要的头文件和符号信息。
核心命令示例:
# 下载内核源码
wget https://cdn.kernel.org/pub/linux/kernel/v5.x/linux-5.10.210.tar.xz
tar -xf linux-5.10.210.tar.xz -C /home/user/
cd /home/user/linux-5.10.210
# 生成默认配置
make defconfig
# 准备模块编译环境
make modules_prepare
我的经验: 我曾经在编译驱动时遇到一堆“未定义的符号”错误,折腾了两天才发现是内核源码树没准备好,modules_prepare 没跑。嗯,从那以后我每次搭建环境都会先确认这一步。
2.2 交叉编译工具链配置
如果你是在x86的PC上开发,目标平台也是x86,那其实不需要交叉编译。但现实是,很多服务器网卡驱动最终要跑在ARM或MIPS架构上。所以交叉编译是必备技能。
什么是交叉编译?
说白了,就是在你的开发机器(x86)上,编译出能在目标机器(比如ARM64)上运行的二进制文件。这需要一套专门的工具链。
配置步骤:
- 安装交叉编译工具链:以ARM64为例,Ubuntu上直接
apt install gcc-aarch64-linux-gnu。如果是其他架构,比如ARM32、MIPS,对应的包名不同。 - 设置环境变量:定义
CROSS_COMPILE和ARCH变量。这样内核的构建系统就知道用哪个编译器。 - 验证工具链:运行
aarch64-linux-gnu-gcc --version,能看到版本信息就说明装好了。
环境变量配置示例:
export ARCH=arm64
export CROSS_COMPILE=aarch64-linux-gnu-
# 验证
${CROSS_COMPILE}gcc --version
注意: 交叉编译工具链的版本要和内核版本匹配。太老的编译器可能不支持新内核的某些语法。我曾经用gcc 4.8编译5.10内核,结果一堆语法错误。后来换成gcc 9.4就没事了。
2.3 QEMU/KVM虚拟化测试环境搭建
驱动写好了,总得跑起来测试吧?你不能每次都往真服务器上刷。万一写崩了,网卡挂了,服务器就失联了。所以我们需要一个虚拟化测试环境。
为什么选QEMU/KVM?
QEMU可以模拟完整的硬件环境,包括PCIe设备。KVM利用硬件虚拟化加速,让虚拟机跑得飞快。两者结合,既能模拟网卡,又有接近原生的性能。
搭建步骤:
- 安装QEMU和KVM:Ubuntu上
apt install qemu-system-arm qemu-efi libvirt-daemon-system。记得确认CPU支持虚拟化(kvm-ok命令检查)。 - 准备根文件系统:可以用Buildroot或Debootstrap制作一个最小的根文件系统。我习惯用Buildroot,因为它能一键生成内核和根文件系统。
- 启动虚拟机:用QEMU命令行启动,指定内核镜像、根文件系统、以及模拟的网卡设备。
- 挂载驱动模块:在虚拟机里用
insmod或modprobe加载你编译好的网卡驱动。
启动QEMU虚拟机示例(ARM64):
qemu-system-aarch64 \
-machine virt \
-cpu cortex-a57 \
-smp 4 \
-m 2G \
-kernel /path/to/Image \
-append "console=ttyAMA0 root=/dev/vda rw" \
-drive file=/path/to/rootfs.ext4,format=raw,if=virtio \
-netdev user,id=net0 \
-device virtio-net-pci,netdev=net0 \
-nographic
避坑指南: 我曾经在QEMU里测试网卡驱动,发现网络不通。查了半天,原来是QEMU默认的网卡模型是 rtl8139,而我编译的是Intel的 igb 驱动。后来加上 -device e1000e 指定Intel网卡模型就正常了。所以记得要指定正确的网卡设备模型。
2.4 环境验证
环境搭好了,怎么知道对不对?我一般做三步验证:
| 验证项 | 命令 | 预期结果 |
|---|---|---|
| 内核源码树 | ls /home/user/linux-5.10.210/include/linux/netdevice.h |
文件存在,可读 |
| 交叉编译工具链 | aarch64-linux-gnu-gcc -E -dM - < /dev/null | grep __aarch64__ |
输出 __aarch64__ 1 |
| QEMU虚拟机 | 在虚拟机内运行 lspci | grep Ethernet |
能看到模拟的Intel网卡设备 |
这三步都过了,你的开发环境就算搭好了。后面我们就可以开始写真正的网卡驱动代码了。
总结一下:
- 内核源码树是驱动开发的“字典”,必须准备好。
- 交叉编译工具链让你能在PC上编译出目标平台的驱动。
- QEMU/KVM是安全的测试沙箱,随便折腾,不怕搞坏真机。
嗯,这一章就到这。下一章我们开始分析Intel网卡的数据手册,看看硬件到底长什么样。