2. 开发环境搭建
在开始编写和调试Linux内核网络驱动之前,必须搭建一套完整的开发与验证环境。本章将引导你完成三个核心环节:交叉编译工具链的安装与配置、QEMU模拟器搭建ARM64虚拟平台,以及内核源码树的获取与编译。这套环境将贯穿整个课程,用于编译驱动、生成内核镜像并在模拟器中运行调试。
2.1 交叉编译工具链配置
交叉编译是指在主机(x86_64)上编译生成目标平台(ARM64)可执行代码的过程。对于嵌入式Linux开发,这是必备技能。
2.1.1 工具链选择与安装
推荐使用 GNU GCC 交叉编译工具链,针对ARM64目标,常用的前缀为 aarch64-linux-gnu-。在Ubuntu/Debian主机上,可通过包管理器直接安装:
# 安装ARM64交叉编译工具链及必要依赖
sudo apt-get update
sudo apt-get install -y \
gcc-aarch64-linux-gnu \
binutils-aarch64-linux-gnu \
libc6-dev-arm64-cross \
pkg-config \
flex \
bison \
libncurses-dev \
libssl-dev \
device-tree-compiler
安装完成后,验证工具链是否可用:
# 检查交叉编译器版本
aarch64-linux-gnu-gcc --version
# 编写一个简单的C程序测试交叉编译
echo 'int main(void){ return 0; }' > test.c
aarch64-linux-gnu-gcc -o test.arm64 test.c
file test.arm64
# 输出应包含: ELF 64-bit LSB executable, ARM aarch64
2.1.2 工具链组件说明
| 组件 | 命令前缀 | 功能说明 |
|---|---|---|
| C编译器 | aarch64-linux-gnu-gcc |
编译C源码为ARM64目标文件 |
| C++编译器 | aarch64-linux-gnu-g++ |
编译C++源码为ARM64目标文件 |
| 汇编器 | aarch64-linux-gnu-as |
汇编ARM64汇编代码 |
| 链接器 | aarch64-linux-gnu-ld |
链接目标文件生成可执行文件或内核镜像 |
| 目标文件工具 | aarch64-linux-gnu-objdump |
反汇编、查看目标文件信息 |
| 二进制文件工具 | aarch64-linux-gnu-objcopy |
格式转换,如ELF转纯二进制 |
CROSS_COMPILE 明确指定前缀。内核编译时,若未设置此变量,将默认使用主机本地gcc,导致生成x86_64架构镜像,无法在ARM64 QEMU中运行。
2.1.3 交叉编译环境变量设置
为简化后续操作,建议将交叉编译前缀写入环境变量或Makefile中:
# 设置交叉编译前缀(可写入 ~/.bashrc 永久生效)
export CROSS_COMPILE=aarch64-linux-gnu-
export ARCH=arm64
# 验证环境变量
echo $CROSS_COMPILE
echo $ARCH
2.2 QEMU模拟器搭建ARM64平台
QEMU是一款支持多种架构的硬件模拟器。我们将使用它模拟一个ARM64虚拟开发板,用于运行编译好的内核和网络驱动。
2.2.1 QEMU安装与ARM64支持
# 安装QEMU及ARM64系统模拟器
sudo apt-get install -y qemu-system-arm qemu-utils
# 验证安装
qemu-system-aarch64 --version
2.2.2 模拟平台选择:virt
QEMU为ARM64提供了多种模拟机器类型,本课程选用 virt 平台。它专为虚拟化设计,支持PCIe、GICv3中断控制器、多核SMP等特性,非常适合网络驱动开发与调试。
| 特性 | virt 平台支持 | 驱动开发意义 |
|---|---|---|
| CPU | cortex-a53 / cortex-a72 等 | 支持多核SMP,可测试并发 |
| 内存 | 最大1TB | 满足大内存调试需求 |
| PCIe总线 | 支持 | 可挂载虚拟网卡设备 |
| 中断控制器 | GICv3 | 支持MSI/MSI-X中断 |
| 网络设备 | virtio-net-pci | 标准虚拟网卡,驱动模型清晰 |
2.2.3 启动QEMU验证环境
使用以下命令启动一个最小化的ARM64虚拟机(需要先编译内核,见2.3节):
# 启动QEMU ARM64 virt 平台
qemu-system-aarch64 \
-machine virt \
-cpu cortex-a72 \
-smp 2 \
-m 512M \
-kernel arch/arm64/boot/Image \
-append "console=ttyAMA0 root=/dev/vda rw" \
-drive file=rootfs.ext4,format=raw,if=virtio \
-netdev user,id=net0 \
-device virtio-net-pci,netdev=net0 \
-nographic
-machine virt 选择模拟平台;-cpu cortex-a72 指定CPU型号;-smp 2 分配2个虚拟CPU核心;-device virtio-net-pci 添加虚拟网卡,这是后续驱动实验的目标设备。
2.3 内核源码树准备与编译
内核源码树是驱动开发的基础。我们需要获取Linux内核源码,配置并交叉编译生成ARM64内核镜像和设备树文件。
2.3.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.3.2 内核配置
针对QEMU virt平台,使用默认的ARM64配置并启用必要的网络驱动选项:
# 使用ARM64默认配置
make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- defconfig
# 进一步定制,启用virtio网络和PCIe支持
make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- menuconfig
在menuconfig界面中,确保以下选项被启用(标记为 [*] 或 <M>):
| 配置路径 | 选项名称 | 说明 |
|---|---|---|
| Device Drivers → Network device support | NET_VENDOR_VIRTIO |
启用virtio网卡厂商驱动 |
| Device Drivers → Network device support | VIRTIO_NET |
virtio网络设备驱动(核心) |
| Device Drivers → PCI support | PCI |
PCIe总线支持 |
| Device Drivers → PCI support | PCI_MSI |
MSI中断支持(网络驱动必需) |
| Device Drivers → Virtio drivers | VIRTIO_PCI |
virtio PCI传输层 |
2.3.3 编译内核与设备树
# 编译内核镜像(使用多核加速)
make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- -j$(nproc) Image
# 编译设备树文件(.dtb)
make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- -j$(nproc) dtbs
# 编译内核模块(可选,用于动态加载驱动)
make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- -j$(nproc) modules
编译成功后,关键输出文件位置:
- 内核镜像:
arch/arm64/boot/Image - 设备树文件:
arch/arm64/boot/dts/qemu/qemu-virt.dtb(或类似路径) - 内核模块:分散在源码树各目录下的
.ko文件
make -j$(nproc) 并行编译。如果主机内存充足,可以设置 KCFLAGS="-O2 -pipe" 进一步加速。首次完整编译约需10-30分钟,后续增量编译仅需数秒。
2.3.4 验证编译产物
# 确认内核镜像为ARM64格式
file arch/arm64/boot/Image
# 输出: ... MSB image, Linux kernel ARM64 ...
# 确认设备树文件
fdtdump arch/arm64/boot/dts/qemu/qemu-virt.dtb | head -20
# 应显示设备树版本和节点信息
2.4 环境验证:启动最小系统
使用编译好的内核和预先制作的最小根文件系统(rootfs),启动QEMU验证整个工具链是否正常工作:
# 使用busybox制作最小根文件系统(或下载预编译镜像)
# 此处假设已准备好 rootfs.ext4
qemu-system-aarch64 \
-machine virt \
-cpu cortex-a72 \
-smp 2 \
-m 512M \
-kernel linux-6.1.76/arch/arm64/boot/Image \
-dtb linux-6.1.76/arch/arm64/boot/dts/qemu/qemu-virt.dtb \
-append "console=ttyAMA0 root=/dev/vda rw" \
-drive file=rootfs.ext4,format=raw,if=virtio \
-netdev user,id=net0 \
-device virtio-net-pci,netdev=net0 \
-nographic
启动后,在QEMU控制台内应能看到内核启动日志,并最终进入shell提示符。使用以下命令验证网络设备:
# 在QEMU虚拟机内执行
ip link show
# 应显示 eth0 或 enp0s1 等网络接口
# 查看中断信息
cat /proc/interrupts | grep virtio
# 应显示 virtio-net 对应的中断号
2.5 常见问题与排错
| 问题现象 | 可能原因 | 解决方案 |
|---|---|---|
| QEMU启动后无输出 | 未指定 -nographic 或控制台参数错误 |
添加 -nographic 并确保 console=ttyAMA0 |
内核崩溃:Kernel panic - not syncing: VFS: Unable to mount root fs |
根文件系统未正确挂载 | 检查 -drive 参数路径和格式,确认rootfs包含ext4文件系统 |
| 网络接口未出现 | 内核未启用virtio-net驱动 | 检查内核配置中 VIRTIO_NET 和 VIRTIO_PCI 是否启用 |
编译错误:aarch64-linux-gnu-gcc: command not found |
工具链未安装或PATH未设置 | 运行 sudo apt-get install gcc-aarch64-linux-gnu |
| 设备树文件未找到 | 编译时未执行 make dtbs |
执行 make ARCH=arm64 dtbs 生成.dtb文件 |