1. 课程导学与实验环境搭建

嵌入式Linux内核开发,说白了就是给硬件穿上操作系统这件"衣服"。我做了十几年内核开发,见过太多人一上来就啃源码,结果被编译环境折腾得半途而废。所以这一章,我们先搭好台子,再唱戏。

1.1 嵌入式Linux内核开发全景图

先看看我们要学什么,整个知识体系长什么样。

嵌入式Linux内核开发全景图 内核定制与调试与故障定位 内核裁剪与编译 驱动开发与调试 故障定位与优化 Kconfig / Makefile 设备树配置 内核模块编译 字符设备驱动 中断与并发 DMA / 内存映射 Oops / Panic 分析 kgdb / kdump 性能剖析 实验环境:Ubuntu + 交叉工具链 + QEMU + ARM开发板 本课程覆盖从环境搭建到实战调试全流程

这张图我画了很多次。每次带新人,我都会先让他们看这个框架。内核开发不是零散的知识点,而是一整套工程方法。

1.2 课程目标与学习方法

这门课要解决什么问题?说白了就三个:

  • 能定制 —— 根据硬件裁剪内核,去掉不需要的功能
  • 能调试 —— 驱动出问题了,知道怎么定位
  • 能排障 —— 系统崩溃了,能快速找到根因

我个人的学习建议是:别只看,要动手。每章我都会给实验,你跟着敲一遍,比看十遍书都管用。

学习节奏建议

  • 前5章:打好环境基础,别跳步
  • 中间15章:跟着实验走,每章至少跑通一个例子
  • 后10章:综合实战,尝试自己复现故障场景

1.3 Ubuntu虚拟机与交叉编译工具链安装

先搞定开发机。我推荐用 Ubuntu 22.04 LTS,64位版本。为什么?因为社区支持最好,遇到问题搜一下就有答案。

1.3.1 虚拟机安装要点

配置项 推荐值 说明
CPU核心数 4核以上 编译内核时多核并行能省大量时间
内存 8GB以上 低于4GB编译大型内核会卡死
磁盘 80GB以上 内核源码+编译产物很占空间
网络 桥接模式 方便后续与开发板通信

注意:磁盘空间别省。我见过有人只分40GB,编译到一半报磁盘满,还得重新扩容,浪费时间。

1.3.2 交叉编译工具链安装

交叉编译,就是在x86电脑上编译出ARM能跑的程序。工具链我推荐用 Linaro 的 gcc-arm-linux-gnueabihf。

# 安装依赖
sudo apt update
sudo apt install -y build-essential git vim

# 下载交叉编译工具链
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

# 配置环境变量(写入 ~/.bashrc)
export PATH=$PATH:/opt/gcc-linaro-7.5.0-2019.12-x86_64_arm-linux-gnueabihf/bin

# 验证安装
arm-linux-gnueabihf-gcc --version

验证成功会看到版本号。嗯,这里要注意:路径别写错,我刚开始学的时候经常把路径拼错,然后报"command not found",排查半天才发现是少了个斜杠。

1.4 QEMU模拟器与ARM开发板环境搭建

没有开发板怎么办?用QEMU模拟。有板子怎么办?直接烧录。两种方式我都讲。

1.4.1 QEMU模拟ARM环境

QEMU可以模拟ARM的vexpress-a9开发板。我习惯用这个板型,因为Linux内核主线对它支持最好。

# 安装QEMU
sudo apt install -y qemu-system-arm

# 下载内核与文件系统(以4.19内核为例)
wget https://cdn.kernel.org/pub/linux/kernel/v4.x/linux-4.19.tar.xz
tar -xf linux-4.19.tar.xz

# 配置内核(vexpress_defconfig)
cd linux-4.19
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- vexpress_defconfig

# 编译内核
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- -j4

# 启动QEMU
qemu-system-arm \
  -M vexpress-a9 \
  -kernel arch/arm/boot/zImage \
  -dtb arch/arm/boot/dts/vexpress-v2p-ca9.dtb \
  -append "console=ttyAMA0" \
  -nographic

关键点:

  • -M 指定机器类型,vexpress-a9 是最常用的
  • -kernel 指定内核镜像,就是编译出来的 zImage
  • -dtb 指定设备树,描述硬件信息
  • -nographic 用终端模拟串口,不用图形界面

启动后你会看到内核启动日志,最后停在 VFS: Cannot open root device。别慌,这是正常的——我们还没挂载根文件系统。后面章节会教你怎么制作根文件系统。

1.4.2 真实ARM开发板环境

如果你有开发板,比如树莓派或友善之臂的板子,流程类似:

  1. 在Ubuntu上交叉编译内核
  2. 将zImage和设备树文件拷贝到SD卡
  3. 设置开发板从SD卡启动
  4. 通过串口或SSH登录调试
开发板 内核配置 启动方式
树莓派3B+ bcm2837_defconfig SD卡 + config.txt
友善之臂NanoPi nanopi_defconfig SD卡 + boot.scr
QEMU vexpress vexpress_defconfig 命令行直接启动

我的建议:刚开始用QEMU就够了。等把内核编译、驱动加载这些流程跑熟了,再上真实板子。不然板子坏了、线接错了,排查起来很痛苦。我曾经烧录时把SD卡分区表搞坏了,折腾了一下午才恢复。

1.5 环境验证

环境搭好了,怎么确认没问题?跑一个最简单的内核模块试试。

// hello.c
#include <linux/module.h>
#include <linux/kernel.h>

static int __init hello_init(void)
{
    printk(KERN_INFO "Hello, Embedded Linux!\n");
    return 0;
}

static void __exit hello_exit(void)
{
    printk(KERN_INFO "Goodbye!\n");
}

module_init(hello_init);
module_exit(hello_exit);
MODULE_LICENSE("GPL");
# Makefile
obj-m := hello.o

all:
    make -C /path/to/linux-4.19 M=$(PWD) ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- modules

clean:
    make -C /path/to/linux-4.19 M=$(PWD) ARCH=arm clean

编译通过后,把 hello.ko 放到QEMU的文件系统里,用 insmod hello.ko 加载。如果看到 Hello, Embedded Linux! 打印出来,恭喜你,环境全部就绪。

常见坑:

  • 内核版本与工具链不匹配 —— 用4.19内核配7.5工具链没问题
  • Makefile里的路径写错 —— 用绝对路径最保险
  • 模块编译出来是x86格式 —— 检查CROSS_COMPILE是否生效