2. Linux内核源码结构:内核源码目录结构解析、关键子目录功能与获取方法
理解Linux内核源码的目录结构是驱动开发的基石。内核源码经过数十年的演进,形成了高度模块化、层次清晰的目录组织方式。本章将深入剖析内核源码的顶层目录布局、关键子目录的核心职责,并介绍获取与查看源码的实用方法。
学习提示: 本章内容不要求死记硬背每个目录下的文件名,而是建立对内核源码“地图”的整体认知。后续编写驱动时,你将频繁穿梭于
drivers/、include/、arch/ 等目录之间。
2.1 内核源码顶层目录结构总览
一个标准的内核源码根目录(以Linux 6.x为例)包含约20个一级子目录。下图展示了核心目录的层级关系与数据流向:
2.2 关键子目录功能详解
下表总结了驱动开发中最常打交道的8个核心目录及其功能定位:
| 目录名 | 全称 | 核心功能 | 驱动开发者关注点 |
|---|---|---|---|
| arch/ | Architecture | CPU体系结构相关代码,包括启动、内存管理、中断、DMA等硬件底层操作 | 移植驱动时需关注 arch/arm/、arch/arm64/ 下的板级文件 |
| drivers/ | Device Drivers | 所有设备驱动的实现,按子系统分类(char、i2c、spi、net、usb等) | 驱动开发主战场,90%的编码工作在此完成 |
| fs/ | File Systems | 虚拟文件系统(VFS)及具体文件系统实现(ext4、proc、sysfs等) | 驱动通过 fs/sysfs/ 导出属性,通过 fs/proc/ 调试 |
| include/ | Include Headers | 内核头文件,分为 linux/(通用)、uapi/(用户态API)、asm-*/(体系相关) |
驱动必须包含的头文件来源,如 <linux/module.h> |
| kernel/ | Kernel Core | 内核核心功能:进程调度、信号、时间管理、工作队列、printk等 | 驱动使用 kernel/workqueue.c、kernel/irq/ 等基础设施 |
| mm/ | Memory Management | 内存管理子系统:页分配、slab分配器、内存映射、CMA等 | 驱动使用 kmalloc、dma_alloc_coherent 等API |
| net/ | Networking | 网络协议栈实现(TCP/IP、socket、网络设备框架) | 网络驱动开发时需理解 net/core/ 和 net/sched/ |
| Documentation/ | Documentation | 内核文档,包含设备树绑定、驱动API说明、子系统使用指南 | 编写驱动前应查阅 Documentation/devicetree/ 和 Documentation/driver-api/ |
2.3 驱动开发核心目录深入分析
2.3.1 drivers/ — 驱动代码的主仓库
drivers/ 是内核中最大的目录,按设备类型和总线分为数十个子目录。以下是与嵌入式驱动开发最相关的子目录:
- char/:字符设备驱动,如
mem.c(/dev/mem)、random.c(/dev/random) - i2c/:I2C总线及设备驱动,包含
i2c-core.c和大量传感器、EEPROM驱动 - spi/:SPI总线驱动,包含
spi.c核心框架和SPI设备驱动 - gpio/:GPIO子系统驱动,包含
gpiolib.c和芯片驱动 - pinctrl/:引脚控制子系统,管理引脚复用和电气属性
- regulator/:电压调节器驱动框架
- clk/:时钟框架驱动,管理设备时钟使能与频率
- dma/:DMA引擎驱动框架
- input/:输入子系统(触摸、按键、鼠标等)
- media/:多媒体驱动(摄像头、视频编解码)
- net/:网络设备驱动(以太网、无线、CAN等)
- usb/:USB主机/设备/OTG驱动
- mmc/:MMC/SD/SDIO卡驱动
- mtd/:内存技术设备驱动(NAND Flash、SPI NOR)
- staging/:暂存目录,存放未完全符合内核编码规范的驱动
实战经验: 编写一个新的I2C温度传感器驱动时,你应当将源文件放在
drivers/i2c/ 下,并在该目录的 Kconfig 和 Makefile 中添加对应配置项。不要随意在其他目录创建文件,保持内核目录结构的整洁。
2.3.2 include/ — 内核API的“字典”
include/ 目录是驱动开发者的“头文件宝库”,其子目录结构如下:
| 子目录 | 内容 | 驱动常用头文件示例 |
|---|---|---|
include/linux/ |
通用内核头文件,与体系结构无关 | <linux/module.h>、<linux/fs.h>、<linux/platform_device.h> |
include/uapi/ |
用户空间API头文件,系统调用和ioctl命令定义 | <uapi/linux/ioctl.h>、<uapi/linux/i2c.h> |
include/asm-generic/ |
体系结构无关的汇编/硬件抽象头文件 | <asm-generic/io.h>、<asm-generic/gpio.h> |
include/dt-bindings/ |
设备树绑定头文件,定义宏和常量 | <dt-bindings/gpio/gpio.h>、<dt-bindings/interrupt-controller/irq.h> |
include/trace/ |
trace事件头文件,用于驱动调试 | <trace/events/i2c.h> |
2.3.3 arch/ — 体系结构相关代码
嵌入式开发中,arch/arm/ 和 arch/arm64/ 是最常接触的目录。其内部结构通常包含:
- boot/:启动代码(汇编启动、设备树编译脚本)
- configs/:默认内核配置文件(如
multi_v7_defconfig) - include/:体系结构相关的头文件(如
asm/io.h、asm/memory.h) - kernel/:体系结构相关的核心代码(时钟、中断、信号处理)
- mm/:体系结构相关的内存管理代码
- mach-*/:特定SoC厂商的板级支持代码(旧内核风格,新内核已迁移到设备树)
- plat-*/:平台通用代码(多个SoC共享)
注意: 在4.x以后的内核中,传统的
mach-*/ 和 plat-*/ 目录逐渐被设备树(Device Tree)取代。新板卡支持不再需要修改 arch/arm/mach-*/ 下的C代码,而是通过编写 .dts 设备树源文件来描述硬件。
2.4 如何获取内核源码
获取内核源码有四种主流方式,按使用场景推荐如下:
| 方式 | 命令/链接 | 适用场景 | 优点 |
|---|---|---|---|
| 1. Git克隆主线仓库 | git clone git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git |
开发、学习最新内核 | 获取完整历史,可切换任意标签和分支 |
| 2. 下载稳定版tarball | wget https://cdn.kernel.org/pub/linux/kernel/v6.x/linux-6.x.tar.xz |
嵌入式产品开发 | 体积小、版本固定、适合离线编译 |
| 3. 发行版源码包 | apt-get install linux-source-6.x (Debian/Ubuntu) |
与当前系统内核版本匹配 | 自动适配发行版补丁和配置 |
| 4. SoC厂商提供的内核 | 从NXP、TI、Rockchip等厂商的GitHub或官网获取 | 特定硬件平台开发 | 包含板级支持包(BSP)和预置配置 |
推荐做法: 对于本课程的学习,建议使用方式1或2获取主线内核(如6.x LTS版本)。厂商BSP通常包含大量非主线代码,不利于学习标准驱动框架。
2.5 查看内核源码的实用方法
高效浏览内核源码是驱动开发的基本功。以下是三种常用方法:
2.5.1 命令行工具
# 查找函数定义
grep -r "function_name" --include="*.c" --include="*.h"
# 使用cscope建立索引(推荐)
cscope -Rbkq
# 然后在vim中使用 :cs find c function_name
# 使用ctags生成标签
ctags -R .
# 在vim中 Ctrl+] 跳转到定义,Ctrl+T 返回
2.5.2 图形化工具
- Source Insight:Windows下经典内核源码阅读工具,支持实时解析和跳转
- VS Code + clangd:Linux下推荐,安装C/C++插件和clangd后支持精确跳转
- Elixir Cross Referencer:在线内核源码浏览器(
https://elixir.bootlin.com/linux/latest/source)
2.5.3 内核源码中的文档
# 内核文档目录
Documentation/
├── devicetree/ # 设备树绑定文档
├── driver-api/ # 驱动API文档
│ ├── i2c.rst
│ ├── spi.rst
│ └── gpio/
├── filesystems/ # 文件系统文档
├── networking/ # 网络子系统文档
└── process/ # 内核开发流程文档
关键技巧: 在阅读驱动源码时,先看
Documentation/driver-api/ 下对应子系统的文档,再结合 drivers/ 下的示例驱动,最后查阅 include/linux/ 中的头文件API声明。这个“文档→示例→API”的三步法能大幅提升源码理解效率。
2.6 本章小结
通过本章的学习,你应该掌握了以下核心知识点:
- 内核源码顶层目录的布局和每个目录的定位
drivers/、include/、arch/三个驱动开发核心目录的详细结构- 获取内核源码的四种方式及其适用场景
- 使用命令行和图形化工具高效查看内核源码的方法