内核源码目录结构:从根目录看懂Linux内核
说实话,我第一次打开Linux内核源码的时候,整个人是懵的。几千个文件夹,几万个文件,完全不知道从哪下手。后来跟着前辈一点点啃,才慢慢摸清了门道。
今天我就带你走一遍内核源码的顶层目录。这些目录就像城市的各个功能区——有的管交通,有的管通信,有的管安全。搞清楚了它们,你以后裁剪内核、调试驱动,心里就有底了。
核心观点:内核源码的顶层目录,每个都对应一个独立的功能子系统。理解它们,就等于拿到了内核的“地图”。
1. arch/ —— 架构相关代码
这是内核里最“硬”的部分。arch 是 architecture 的缩写,存放着针对不同CPU架构的代码。
你想想看,ARM和x86的启动流程能一样吗?中断处理能一样吗?当然不能。所以这部分代码是平台相关的。
- arch/arm/ —— ARM架构,手机、嵌入式设备的主力
- arch/x86/ —— 桌面和服务器,我们最熟悉的平台
- arch/arm64/ —— 64位ARM,现在的服务器和高端手机都在用
- arch/riscv/ —— RISC-V,开源指令集,最近很火
我的经验:做嵌入式开发时,我习惯先看 arch/arm/boot/dts/ 下的设备树文件。有一次调试一块新板子,死活起不来,最后发现是设备树里GPIO的引脚号写错了。嗯,这种坑踩过一次就记住了。
2. block/ —— 块设备层
block 目录管的是硬盘、SSD、U盘这类块设备。它负责I/O调度、请求合并、电梯算法这些底层逻辑。
说白了,你的数据怎么从应用程序写到磁盘上,中间经过哪些排队和优化,都是这里说了算。
关键文件:block/blk-core.c 是块设备的核心,我建议初学者先看这个文件里的函数调用关系。
3. crypto/ —— 加密API
这个目录存放着内核的加密算法实现。AES、SHA、RSA……你能想到的加密算法,这里基本都有。
为什么内核需要加密?文件系统加密(比如fscrypt)、网络加密(IPsec)、设备加密(dm-crypt)都依赖它。
4. drivers/ —— 设备驱动
这是内核里最大的目录,没有之一。它占了整个内核代码量的60%以上。
drivers/ 下面按设备类型分了子目录:
- drivers/gpio/ —— GPIO驱动
- drivers/i2c/ —— I2C总线驱动
- drivers/spi/ —— SPI总线驱动
- drivers/net/ —— 网卡驱动
- drivers/mmc/ —— SD卡、eMMC驱动
- drivers/usb/ —— USB驱动
注意:我曾经在裁剪内核时,把 drivers/ 下的某个目录整个删掉了,结果系统启动后USB鼠标键盘全不认。后来学乖了——裁剪驱动时,先看 Kconfig 和 Makefile,搞清楚依赖关系再动手。
5. fs/ —— 文件系统
fs 目录实现了各种文件系统。ext4、btrfs、xfs、fat、ntfs……每种文件系统在这里都有一个子目录。
文件系统的核心是 VFS(虚拟文件系统)层,它在上层应用和底层存储之间搭了一座桥。你执行 open()、read()、write() 这些系统调用时,最终都会走到 fs/ 下的代码。
6. include/ —— 头文件
这是内核的“公共接口”。所有模块共享的数据结构、宏定义、函数声明都在这里。
- include/linux/ —— 核心头文件,比如 list.h、spinlock.h
- include/uapi/ —— 用户空间和内核空间的接口定义
- include/asm-generic/ —— 架构无关的汇编头文件
7. init/ —— 内核初始化
init 目录是内核的“入口”。从 start_kernel() 函数开始,内核的整个初始化流程都在这里。
我记得第一次看 init/main.c 时,被里面密密麻麻的函数调用吓到了。其实不用怕,你只需要关注几个关键点:
- setup_arch() —— 架构相关的初始化
- sched_init() —— 调度器初始化
- rest_init() —— 启动第一个用户进程
8. ipc/ —— 进程间通信
IPC 是 Inter-Process Communication 的缩写。这个目录实现了:
- 信号量(semaphore)
- 消息队列(message queue)
- 共享内存(shared memory)
这些机制让不同的进程可以互相通信、同步数据。
9. kernel/ —— 内核核心
这是内核的“大脑”。调度器、进程管理、信号处理、时间管理……这些最核心的功能都在这里。
kernel/sched/ 下面就是调度器的代码。CFS(完全公平调度器)的实现就在这个目录里。
10. lib/ —— 内核库函数
lib 目录提供了一些通用的工具函数,比如:
- 字符串操作(string.c)
- 链表操作(list_sort.c)
- CRC校验(crc32.c)
- 红黑树(rbtree.c)
这些函数在内核各个模块里被广泛使用。
11. mm/ —— 内存管理
mm 目录实现了虚拟内存、页分配、slab分配器、内存映射等机制。
为什么这个目录重要?因为内存是系统最宝贵的资源之一。mm/ 下的代码决定了你的程序能申请多少内存、申请速度有多快。
12. net/ —— 网络协议栈
net 目录实现了整个网络协议栈。从链路层到应用层,TCP/IP、UDP、ICMP、ARP……全在这里。
net/ipv4/ 下面是TCP和UDP的实现。net/core/ 是网络核心层,比如sk_buff结构体的操作。
13. scripts/ —— 编译脚本
scripts 目录存放着内核编译时用到的各种脚本和工具。比如:
- Kconfig 解析脚本
- 设备树编译工具
- 模块签名工具
做内核裁剪时,你经常要跟 scripts/kconfig/ 下的代码打交道。
14. security/ —— 安全模块
security 目录实现了内核的安全框架。SELinux、AppArmor、Tomoyo 这些安全模块都在这里。
它还提供了 LSM(Linux Security Module)框架,允许第三方安全模块以插件形式接入内核。
15. sound/ —— 音频子系统
sound 目录实现了音频驱动和ALSA(高级Linux声音架构)。
ALSA 是现代Linux音频的基石。它提供了统一的音频接口,让应用程序不用关心底层硬件差异。
16. usr/ —— 初始ramfs
usr 目录用于生成 initramfs(初始内存文件系统)。initramfs 是内核启动早期加载的一个临时根文件系统,里面包含了必要的驱动和工具。
17. virt/ —— 虚拟化
virt 目录实现了KVM(基于内核的虚拟机)的代码。它让Linux可以充当Hypervisor,运行其他操作系统。
我最近在做一个嵌入式虚拟化项目,virt/ 下的代码帮了大忙。
总结一下:内核源码的顶层目录,每个都有明确的职责。做内核裁剪时,你只需要关注你需要的功能对应的目录。比如做嵌入式系统,重点看 arch/、drivers/、fs/;做网络设备,重点看 net/、drivers/net/。
我的建议:刚开始接触内核源码时,不要试图一次性搞懂所有目录。先挑一个你最感兴趣的子系统,比如网络或文件系统,深入进去。等熟悉了一个,再看其他的就轻松多了。
好了,这一章就到这里。记住这些目录的作用,后面我们做内核裁剪时,你会经常用到它们。