2. 内核开发环境搭建
嵌入式Linux与Android内核驱动开发的第一步,是构建一个稳定、可复现的开发环境。本章将系统讲解交叉编译工具链的配置、内核源码的获取与编译方法,以及QEMU与Android模拟器的搭建流程。掌握这些基础技能,是后续编写和调试驱动程序的前提。
学习目标:
- 理解交叉编译的原理与工具链结构
- 掌握从官方仓库获取内核源码的方法
- 独立完成内核编译与设备树生成
- 搭建QEMU模拟环境与Android模拟器
2.1 交叉编译工具链配置
交叉编译是指在宿主机(通常是x86架构的PC)上编译生成目标平台(如ARM、AArch64、RISC-V)可执行代码的过程。Android内核与嵌入式Linux内核均依赖交叉编译工具链。
2.1.1 工具链组成
一个完整的交叉编译工具链包含以下核心组件:
| 组件 | 说明 | 典型名称(ARM64) |
|---|---|---|
| 编译器 | 将C/C++源码编译为目标架构的汇编 | aarch64-linux-gnu-gcc |
| 汇编器 | 将汇编代码转换为机器码 | aarch64-linux-gnu-as |
| 链接器 | 将目标文件链接为可执行文件或内核镜像 | aarch64-linux-gnu-ld |
| 库文件 | 目标架构的C标准库与内核头文件 | libc.so.6 (ARM64) |
| 调试器 | 用于目标架构的远程调试 | aarch64-linux-gnu-gdb |
| 二进制工具 | objdump、objcopy、strip等 | aarch64-linux-gnu-objdump |
2.1.2 安装预编译工具链
推荐使用Linaro或Android NDK提供的预编译工具链,避免从源码构建的复杂性。以下以Ubuntu 22.04 LTS为例:
# 安装ARM64交叉编译工具链(用于QEMU与Android内核)
sudo apt-get update
sudo apt-get install -y gcc-aarch64-linux-gnu g++-aarch64-linux-gnu
# 安装ARM32交叉编译工具链(用于旧版Android设备)
sudo apt-get install -y gcc-arm-linux-gnueabihf g++-arm-linux-gnueabihf
# 安装Android NDK(用于编译Android内核模块)
wget https://dl.google.com/android/repository/android-ndk-r26d-linux.zip
unzip android-ndk-r26d-linux.zip
export PATH=$PATH:$(pwd)/android-ndk-r26d/toolchains/llvm/prebuilt/linux-x86_64/bin
注意:Android NDK从r23版本开始,默认使用Clang/LLVM工具链,不再包含GCC。如果编译旧版Android内核(4.19以下),建议使用Linaro GCC工具链。
2.1.3 验证工具链
安装完成后,通过以下命令验证工具链是否正常工作:
# 检查编译器版本
aarch64-linux-gnu-gcc --version
# 编译一个简单的测试程序
cat > hello.c << EOF
#include <stdio.h>
int main() {
printf("Hello, ARM64 Kernel!\n");
return 0;
}
EOF
# 交叉编译
aarch64-linux-gnu-gcc -o hello.arm64 hello.c
# 查看生成文件的架构信息
file hello.arm64
# 输出示例:ELF 64-bit LSB executable, ARM aarch64, version 1 (SYSV)
2.1.4 工具链配置对比
| 工具链来源 | 适用场景 | 编译器类型 | 推荐版本 |
|---|---|---|---|
| Linaro GCC | 通用嵌入式Linux内核编译 | GCC | 13.2-2023.11 |
| Android NDK | Android内核模块与HAL编译 | Clang/LLVM | r26d |
| Buildroot | 定制化根文件系统与内核 | GCC (自编译) | 2024.02 |
| Yocto/OpenEmbedded | 企业级嵌入式Linux发行版 | GCC (自编译) | Kirkstone (4.0) |
最佳实践:对于Android内核驱动开发,建议同时安装Linaro GCC(用于内核编译)和Android NDK(用于内核模块与用户态测试程序),两者互补。
2.2 内核源码获取与编译
2.2.1 获取内核源码
Linux内核源码可以从多个渠道获取,推荐使用git克隆官方仓库,便于版本切换与补丁管理。
# 方法一:克隆Linux官方主线仓库(推荐)
git clone --depth=1 -b v6.6 https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
cd linux
# 方法二:克隆Android Common Kernel仓库(用于Android设备)
git clone --depth=1 -b android-14-6.6 https://android.googlesource.com/kernel/common
cd common
# 方法三:下载稳定版tar包(适合网络受限环境)
wget https://cdn.kernel.org/pub/linux/kernel/v6.x/linux-6.6.8.tar.xz
tar -xf linux-6.6.8.tar.xz
cd linux-6.6.8
版本选择建议:
- 学习阶段:使用LTS版本(如6.6.x),稳定性好,社区支持完善
- Android开发:使用Android Common Kernel(ACK),与AOSP兼容性最佳
- 生产环境:使用芯片厂商提供的BSP内核(如Qualcomm、MTK)
2.2.2 内核配置
内核编译前需要进行配置,选择需要编译的模块与功能。常用的配置方法有三种:
| 配置命令 | 交互方式 | 适用场景 |
|---|---|---|
make defconfig |
自动生成默认配置 | 快速开始,适用于标准平台 |
make menuconfig |
基于ncurses的文本菜单 | 手动选择模块,最常用 |
make ARCH=arm64 defconfig |
指定架构的默认配置 | 交叉编译时使用 |
# 以ARM64架构为例,配置内核
export ARCH=arm64
export CROSS_COMPILE=aarch64-linux-gnu-
# 生成默认配置(基于ARM64 virt平台,适用于QEMU)
make defconfig
# 或者使用menuconfig进行自定义配置
make menuconfig
# 查看生成的配置文件
ls -la .config
2.2.3 编译内核
内核编译过程包括编译内核镜像、设备树(DTB)和内核模块。以下是完整的编译流程:
# 设置环境变量(每次新终端都需要执行)
export ARCH=arm64
export CROSS_COMPILE=aarch64-linux-gnu-
export INSTALL_MOD_PATH=./modules_install
# 编译内核镜像(使用-jN指定并行任务数,N为CPU核心数+1)
make -j$(nproc) Image.gz
# 编译设备树(DTB)
make -j$(nproc) dtbs
# 编译内核模块
make -j$(nproc) modules
# 安装内核模块到指定目录
make modules_install
# 查看编译产物
ls -lh arch/arm64/boot/Image.gz
ls -lh arch/arm64/boot/dts/qemu/
编译时间参考:在8核CPU、32GB内存的机器上,首次编译ARM64内核约需15-30分钟。后续增量编译通常在1-5分钟内完成。
2.2.4 编译产物说明
| 文件 | 路径 | 说明 |
|---|---|---|
| vmlinux | 源码根目录 | 未压缩的ELF格式内核镜像,包含调试信息 |
| Image | arch/arm64/boot/ | 未压缩的原始内核镜像(无ELF头) |
| Image.gz | arch/arm64/boot/ | gzip压缩的内核镜像,QEMU常用 |
| *.dtb | arch/arm64/boot/dts/ | 编译后的设备树二进制文件 |
| *.ko | 各子目录 | 可加载内核模块(驱动) |
| System.map | 源码根目录 | 内核符号表,用于调试与地址解析 |
2.3 QEMU模拟器环境搭建
QEMU是一款支持多种架构的硬件模拟器,可以在没有真实硬件的情况下运行和调试内核。对于驱动开发,QEMU提供了快速迭代和断点调试的能力。
2.3.1 安装QEMU
# 安装QEMU(支持ARM64架构)
sudo apt-get install -y qemu-system-arm qemu-efi-aarch64
# 验证安装
qemu-system-aarch64 --version
# 输出示例:QEMU emulator version 8.2.0
2.3.2 制作根文件系统
内核启动后需要根文件系统(rootfs)来运行用户态程序。推荐使用Buildroot或BusyBox制作最小根文件系统。
# 使用BusyBox制作最小根文件系统
# 1. 下载BusyBox
wget https://busybox.net/downloads/busybox-1.36.1.tar.bz2
tar -xf busybox-1.36.1.tar.bz2
cd busybox-1.36.1
# 2. 配置并编译
make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- defconfig
make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- -j$(nproc)
make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- install
# 3. 制作根文件系统镜像
cd _install
mkdir -p proc sys dev etc/init.d
cat > etc/init.d/rcS << EOF
#!/bin/sh
mount -t proc none /proc
mount -t sysfs none /sys
mount -t devtmpfs none /dev
echo "Welcome to QEMU ARM64 Linux!"
EOF
chmod +x etc/init.d/rcS
# 4. 打包为cpio归档
find . | cpio -o --format=newc > ../rootfs.cpio
cd ..
gzip -c rootfs.cpio > rootfs.cpio.gz
2.3.3 启动QEMU
# 使用编译好的内核与根文件系统启动QEMU
qemu-system-aarch64 \
-machine virt \
-cpu cortex-a72 \
-smp 4 \
-m 2G \
-kernel arch/arm64/boot/Image.gz \
-initrd /path/to/rootfs.cpio.gz \
-append "console=ttyAMA0 root=/dev/ram rdinit=/sbin/init" \
-nographic \
-netdev user,id=net0 \
-device virtio-net-pci,netdev=net0
# 启动后,在QEMU终端中应看到内核启动日志,最终进入shell提示符
QEMU调试技巧:
- 添加
-s -S参数可在启动时暂停,等待GDB连接(端口1234) - 使用
-d in_asm -D qemu.log记录指令执行日志 - 使用
-drive file=disk.img,format=raw挂载磁盘镜像
2.3.4 QEMU与真实硬件对比
| 特性 | QEMU模拟器 | 真实硬件(如Raspberry Pi) |
|---|---|---|
| 启动速度 | 快(10-30秒) | 慢(1-3分钟) |
| 调试能力 | 支持GDB断点、单步、内存查看 | 需要JTAG或串口调试 |
| 硬件外设 | 模拟通用设备(virtio、PL011) | 真实外设(GPIO、I2C、SPI) |
| 驱动验证 | 适合逻辑验证与原型开发 | 必须进行最终验证 |
| 成本 | 免费 | 需要硬件采购 |
2.4 Android模拟器环境搭建
Android模拟器(基于QEMU)是Android内核驱动开发的另一重要平台。与通用QEMU不同,Android模拟器集成了Goldfish平台专用驱动和Android系统服务。
2.4.1 安装Android Studio与模拟器
# 1. 下载并安装Android Studio
wget https://redirector.gvt1.com/edgedl/android/studio/ide-zips/2023.3.1.18/android-studio-2023.3.1.18-linux.tar.gz
tar -xf android-studio-2023.3.1.18-linux.tar.gz
cd android-studio/bin
./studio.sh
# 2. 在Android Studio中安装SDK与模拟器
# 通过Tools -> SDK Manager 安装:
# - Android SDK Platform 34
# - Android SDK Build-Tools 34
# - Android Emulator (最新版)
# - ARM64系统镜像 (如: system-images;android-34;google_apis;arm64-v8a)
# 3. 命令行创建模拟器(可选)
export ANDROID_HOME=~/Android/Sdk
$ANDROID_HOME/cmdline-tools/latest/bin/sdkmanager "system-images;android-34;google_apis;arm64-v8a"
$ANDROID_HOME/tools/bin/avdmanager create avd -n test_device -k "system-images;android-34;google_apis;arm64-v8a"
2.4.2 编译Android内核(Goldfish)
Android模拟器使用Goldfish内核,该内核包含模拟器专用驱动(如Goldfish RTC、Goldfish Audio等)。
# 1. 克隆Goldfish内核
git clone --depth=1 -b android-14-6.6 https://android.googlesource.com/kernel/goldfish
cd goldfish
# 2. 设置环境变量
export ARCH=arm64
export CROSS_COMPILE=aarch64-linux-gnu-
export PATH=$PATH:~/Android/Sdk/emulator
# 3. 使用Goldfish默认配置
make goldfish_arm64_defconfig
# 4. 编译内核
make -j$(nproc) Image.gz
# 5. 查看编译产物
ls -lh arch/arm64/boot/Image.gz
2.4.3 使用自定义内核启动模拟器
# 1. 找到Android模拟器的内核参数
# 默认内核路径:~/Android/Sdk/system-images/android-34/google_apis/arm64-v8a/kernel-ranchu
# 2. 使用自定义内核启动模拟器
emulator \
-avd test_device \
-kernel /path/to/goldfish/arch/arm64/boot/Image.gz \
-show-kernel \
-verbose \
-no-snapshot \
-memory 2048
# 3. 验证内核版本(在模拟器终端中执行)
adb shell
uname -a
# 输出应显示自定义内核版本信息
注意事项:
- Android模拟器内核必须与系统镜像的API级别匹配,否则可能无法启动
- 使用
-show-kernel参数可以查看内核启动日志,便于调试 - 如果模拟器启动失败,检查
~/.android/avd/test_device.avd/config.ini中的配置
2.4.4 QEMU与Android模拟器对比
| 对比维度 | 通用QEMU | Android模拟器 |
|---|---|---|
| 目标平台 | 通用ARM64/ARM32/RISC-V | ← 上一章 📖 返回目录 下一章 → |