4. 内核源码目录结构解析:arch、drivers、fs、include、kernel、mm、net 等核心目录的作用
Linux 内核源码是一个庞大且高度模块化的工程,理解其顶层目录结构是进行驱动开发的第一步。每个顶层目录都承载着特定的功能领域,驱动开发者需要快速定位关键代码所在位置。本章将逐一解析核心目录的职责、典型子目录以及驱动开发中最常打交道的文件。
4.1 顶层目录全景图
Linux 内核源码根目录下通常包含以下核心目录(以 6.x 版本为例):
核心目录速查表 — 驱动开发最常访问的目录依次为:drivers、include、arch、kernel、Documentation。
| 目录名 | 全称 / 含义 | 驱动开发关联度 | 典型子目录举例 |
|---|---|---|---|
| arch | Architecture(体系结构) | ⭐⭐⭐⭐⭐ | arm、arm64、x86、riscv、mips |
| drivers | Device Drivers(设备驱动) | ⭐⭐⭐⭐⭐ | i2c、spi、gpio、usb、pci、dma、mmc |
| fs | File Systems(文件系统) | ⭐⭐⭐ | ext4、proc、sysfs、debugfs、tmpfs |
| include | Header Files(头文件) | ⭐⭐⭐⭐⭐ | linux、uapi、asm-generic、dt-bindings |
| kernel | Core Kernel(内核核心) | ⭐⭐⭐⭐ | sched、irq、time、power、printk |
| mm | Memory Management(内存管理) | ⭐⭐⭐ | slab、page_alloc、vmalloc、memblock |
| net | Networking(网络协议栈) | ⭐⭐⭐ | ipv4、ipv6、wireless、core、ethernet |
| Documentation | 内核文档 | ⭐⭐⭐⭐ | devicetree、driver-api、filesystems |
| scripts | 编译与辅助脚本 | ⭐⭐⭐ | kconfig、dtc、checkpatch.pl |
4.2 arch/ — 体系结构相关代码
arch/ 目录存放与 CPU 体系结构紧密相关的代码,是内核移植和板级支持包(BSP)的核心区域。每个支持的 CPU 架构在该目录下都有一个独立子目录。
4.2.1 常见架构子目录
- arch/arm/ — 32 位 ARM 架构,嵌入式设备中最常见。
- arch/arm64/ — 64 位 ARMv8 架构,现代 SoC 主流选择。
- arch/x86/ — x86 架构,主要用于 PC 和服务器。
- arch/riscv/ — RISC-V 开源架构,新兴嵌入式平台。
- arch/mips/ — MIPS 架构,部分老旧嵌入式设备仍在使用。
4.2.2 驱动开发者关注点
| 子路径 | 作用 | 驱动开发场景 |
|---|---|---|
arch/arm/boot/dts/ |
设备树源文件(.dts / .dtsi) | 定义硬件拓扑、寄存器地址、中断号 |
arch/arm/mach-xxx/ |
板级初始化代码(旧内核) | 平台设备注册、时钟配置 |
arch/arm/include/asm/ |
架构相关头文件 | IO 操作宏、内存屏障、原子操作 |
arch/arm64/kernel/ |
内核启动与异常处理 | 中断向量、系统调用入口 |
实战提示: 编写 ARM 平台驱动时,设备树文件位于
arch/arm/boot/dts/ 或 arch/arm64/boot/dts/。修改设备树后需要重新编译 DTB 并更新引导加载程序。
4.3 drivers/ — 设备驱动代码主战场
drivers/ 是内核中最大的目录,包含几乎所有外设的驱动实现。驱动开发者的大部分工作都在这个目录下完成。
4.3.1 驱动子系统分类
| 子系统目录 | 包含驱动类型 | 典型文件 |
|---|---|---|
drivers/gpio/ |
GPIO 控制器驱动 | gpio-omap.c, gpio-rockchip.c |
drivers/i2c/ |
I2C 总线控制器 + 从设备驱动 | i2c-imx.c, busses/, algos/ |
drivers/spi/ |
SPI 控制器 + 从设备驱动 | spi-imx.c, spi-rockchip.c |
drivers/mtd/ |
存储设备驱动(NAND、SPI NOR) | nand/, spi-nor/ |
drivers/net/ |
网络接口控制器驱动 | ethernet/, wireless/, phy/ |
drivers/usb/ |
USB 主机/设备/OTG 驱动 | host/, gadget/, core/ |
drivers/mmc/ |
SD/MMC/eMMC 控制器驱动 | host/, core/, card/ |
drivers/dma/ |
DMA 控制器驱动 | dmaengine/ 子目录 |
drivers/clk/ |
时钟控制器驱动 | clk-imx.c, clk-rockchip.c |
drivers/pinctrl/ |
引脚复用与配置驱动 | pinctrl-imx.c |
避坑提醒: 不要直接在
drivers/ 根目录下添加新驱动。应按照外设类型放入对应的子系统子目录。如果找不到合适的子系统,考虑使用 drivers/misc/(杂项设备)或 drivers/staging/(暂存区)。
4.3.2 驱动文件命名惯例
# 典型 SPI 控制器驱动命名
drivers/spi/spi-imx.c # NXP i.MX 系列 SPI 控制器
drivers/spi/spi-rockchip.c # Rockchip SPI 控制器
drivers/spi/spi-bcm2835.c # Broadcom BCM2835 SPI 控制器
# 典型 I2C 控制器驱动命名
drivers/i2c/busses/i2c-imx.c
drivers/i2c/busses/i2c-tegra.c
# 典型 GPIO 控制器驱动命名
drivers/gpio/gpio-omap.c
drivers/gpio/gpio-rockchip.c
4.4 include/ — 内核 API 头文件仓库
include/ 目录是内核提供给驱动开发者的“API 手册”。驱动代码通过包含这些头文件来使用内核提供的函数、宏和数据结构。
4.4.1 头文件分类
| 子目录 | 内容 | 驱动常用头文件 |
|---|---|---|
include/linux/ |
通用内核 API 头文件 | module.h, platform_device.h, gpio.h, i2c.h, spi.h |
include/uapi/ |
用户空间 API 头文件 | ioctl.h, types.h, stat.h |
include/asm-generic/ |
体系结构无关的通用头文件 | io.h, atomic.h, bitops.h |
include/dt-bindings/ |
设备树绑定头文件 | gpio.h, clock.h, interrupt.h |
include/soc/ |
SoC 特定头文件 | imx8m.h, rockchip.h |
驱动开发黄金法则: 编写驱动时,优先查阅
include/linux/ 下的头文件。例如 #include <linux/module.h> 是所有内核模块必须包含的头文件。
4.5 fs/ — 文件系统与驱动接口
fs/ 目录实现各种文件系统,驱动开发者主要关注其中与设备模型交互的部分:
- procfs (
fs/proc/) — 通过/proc接口暴露内核信息,驱动可用proc_create()创建条目。 - sysfs (
fs/sysfs/) — 通过/sys接口暴露设备属性,驱动通过device_create_file()添加。 - debugfs (
fs/debugfs/) — 调试文件系统,驱动开发阶段常用debugfs_create_dir()和debugfs_create_file()。 - tmpfs (
fs/tmpfs/) — 临时文件系统,用于内存文件存储。
// 驱动中使用 debugfs 的典型代码片段
#include <linux/debugfs.h>
static struct dentry *debugfs_dir;
static int __init my_driver_init(void)
{
debugfs_dir = debugfs_create_dir("my_driver", NULL);
if (IS_ERR(debugfs_dir))
return PTR_ERR(debugfs_dir);
debugfs_create_u32("reg_value", 0644, debugfs_dir, &my_reg_value);
return 0;
}
static void __exit my_driver_exit(void)
{
debugfs_remove_recursive(debugfs_dir);
}
4.6 kernel/ — 内核核心机制
kernel/ 目录包含内核的核心子系统,驱动开发中会频繁调用其中的函数:
| 子目录 / 文件 | 功能 | 驱动常用接口 |
|---|---|---|
kernel/sched/ |
进程调度 | schedule(), wake_up_process() |
kernel/irq/ |
中断子系统 | request_irq(), free_irq(), tasklet |
kernel/time/ |
时间与定时器 | timer_list, hrtimer, jiffies |
kernel/printk.c |
内核日志 | printk(), pr_info(), dev_err() |
kernel/workqueue.c |
工作队列 | schedule_work(), queue_work() |
4.7 mm/ — 内存管理
mm/ 目录实现虚拟内存、页分配、slab 分配器等。驱动开发者主要使用以下接口:
- kmalloc / kfree — 内核内存分配,基于 slab 分配器。
- vmalloc / vfree — 虚拟地址连续但物理地址不连续的内存分配。
- dma_alloc_coherent — DMA 一致性内存分配,位于
drivers/base/dma-coherent.c。 - ioremap / iounmap — IO 内存映射,将物理地址映射到内核虚拟地址空间。
// 驱动中常见的内存操作模式
void __iomem *base_addr;
// 1. 映射物理地址到内核虚拟空间
base_addr = ioremap(0x1C00000, SZ_4K);
if (!base_addr) {
pr_err("ioremap failed\n");
return -ENOMEM;
}
// 2. 读写寄存器
u32 val = readl(base_addr + 0x10);
writel(val | BIT(0), base_addr + 0x10);
// 3. 解除映射
iounmap(base_addr);
4.8 net/ — 网络协议栈
net/ 目录实现完整的网络协议栈。网络设备驱动开发者需要关注:
- net/core/ — 网络核心层,包括
net_device结构体操作、sk_buff 管理。 - net/ethernet/ — 以太网协议相关代码。
- net/wireless/ — 无线网络子系统(cfg80211、mac80211)。
- net/ipv4/ 和 net/ipv6/ — TCP/IP 协议栈实现。
学习路径建议: 网络驱动开发入门可以从
drivers/net/ethernet/ 下的简单以太网驱动开始阅读,配合 include/linux/netdevice.h 理解 net_device_ops 结构体。
4.9 其他重要目录
| 目录 | 作用 | 驱动开发用途 |
|---|---|---|
| Documentation/ | 内核文档 | 查阅驱动 API 说明、设备树绑定文档 |
| scripts/ | 编译与配置脚本 | checkpatch.pl 检查代码风格、dtc 编译设备树 |
| tools/ | 用户空间工具 | perf、objtool、testing 等调试工具 |
| samples/ | 内核编程示例 | 参考驱动编写范例 |
| init/ | 内核初始化代码 | main.c 是内核入口,了解启动流程 |
| lib/ | 内核库函数 | kobject、klist、rbtree 等通用数据结构 |