Skip to content

Linux 内核架构总览

内核在系统中的位置

Linux 是一个宏内核(Monolithic Kernel),所有核心服务——进程调度、内存管理、文件系统、网络协议栈、设备驱动——都运行在同一个内核地址空间(Ring 0)。与微内核不同,宏内核的优势是子系统间调用开销极低,代价是任何驱动 bug 都可能导致整个系统崩溃。

┌─────────────────────────────────────────────────────┐
│                   用户空间 (Ring 3)                   │
│   应用程序   Shell   库 (glibc)   守护进程            │
└──────────────────────┬──────────────────────────────┘
                       │  系统调用 (syscall)
┌──────────────────────▼──────────────────────────────┐
│                  内核空间 (Ring 0)                    │
│  ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌────────┐  │
│  │ 进程调度  │ │ 内存管理  │ │ 文件系统  │ │ 网络栈 │  │
│  └──────────┘ └──────────┘ └──────────┘ └────────┘  │
│  ┌─────────────────────────────────────────────────┐ │
│  │              设备驱动层                          │ │
│  └─────────────────────────────────────────────────┘ │
│  ┌─────────────────────────────────────────────────┐ │
│  │         硬件抽象层 / 体系结构相关代码 (arch/)    │ │
│  └─────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────┘

┌──────────────────────▼──────────────────────────────┐
│                      硬件                            │
│   CPU   内存   磁盘   网卡   GPIO   I2C   SPI  ...   │
└─────────────────────────────────────────────────────┘

内核源码目录结构

目录说明
arch/体系结构相关代码(x86、arm、arm64、riscv…)
drivers/所有设备驱动,按子系统分类
fs/文件系统(ext4、btrfs、proc、sysfs…)
include/内核头文件
kernel/核心子系统(调度器、信号、时钟…)
mm/内存管理子系统
net/网络协议栈
lib/通用库(链表、红黑树、位图…)
init/内核启动入口 start_kernel()
Documentation/官方文档与 binding 规范

内核启动流程

上电 → Bootloader (U-Boot/GRUB)
    → 解压内核镜像 (zImage/Image)
    → start_kernel()
        ├── setup_arch()          # 体系结构初始化
        ├── mm_init()             # 内存管理初始化
        ├── sched_init()          # 调度器初始化
        ├── init_IRQ()            # 中断控制器初始化
        ├── time_init()           # 时钟初始化
        ├── rest_init()
        │   ├── kernel_thread(kernel_init)   # PID 1
        │   └── cpu_idle()                   # idle 进程
        └── kernel_init()
            ├── do_initcalls()    # 执行所有 __initcall 注册的函数
            └── 挂载根文件系统,exec /sbin/init

do_initcalls() 是驱动开发者最关心的环节——所有通过 module_init() 注册的驱动初始化函数都在这里按优先级顺序执行。

内核版本与长期支持

类型说明示例
主线版本 (mainline)Linus 维护,每 9-10 周发布6.x
稳定版 (stable)修复 bug,无新特性6.x.y
长期支持版 (LTS)维护 2-6 年,嵌入式首选6.6 LTS、5.15 LTS
发行版内核Ubuntu/RHEL 自行维护,含大量 backport

嵌入式产品建议选用 LTS 版本,避免频繁跟进主线变动。

内核配置系统

内核通过 Kconfig 管理数千个编译选项:

bash
# 图形化配置(推荐)
make menuconfig

# 基于当前运行内核配置
make localmodconfig

# 查看某选项的依赖关系
grep -r "CONFIG_I2C" arch/arm64/configs/

关键配置项(驱动开发必知):

CONFIG_MODULES=y          # 支持可加载模块
CONFIG_MODULE_UNLOAD=y    # 支持卸载模块
CONFIG_KALLSYMS=y         # 符号表(oops 解析必需)
CONFIG_DEBUG_KERNEL=y     # 内核调试支持
CONFIG_DYNAMIC_DEBUG=y    # 动态调试(pr_debug 按需开启)
CONFIG_KASAN=y            # 内存错误检测

内核抢占模型

Linux 提供三种抢占配置,影响驱动的实时性要求:

配置延迟适用场景
PREEMPT_NONE最高吞吐服务器
PREEMPT_VOLUNTARY中等桌面
PREEMPT低延迟嵌入式
PREEMPT_RT(PREEMPT_REALTIME)硬实时工业控制

PREEMPT_RT 补丁将大量自旋锁替换为可睡眠的 rt_mutex,驱动编写时需注意不能在持有 spinlock 时调用可能睡眠的函数。

下一步

褚成志的笔记