本篇定位 :整个 Linux 内核专题的"灵魂"。不写一行代码,只建认知。读完你能 30 秒说清"Linux 内核是什么、为什么这么设计、和 FreeRTOS/RISC-V 本质差异在哪"。这层认知不建,后面 15 篇都是散的零件。
先打破一个误区你可能以为学 Linux 内核 = 背 API。错。Linux 内核 API 几万个,背不完。学内核 = 学它的设计哲学 + 数据结构 + 控制流。哲学告诉你"为什么这么设计",数据结构告诉你"信息怎么组织",控制流告诉你"代码怎么跑"。这三层通了,API 查文档即可。本篇讲第一层------哲学。
目录
- [一、宏内核 vs 微内核(第一个根本选择)](#一、宏内核 vs 微内核(第一个根本选择))
-
- [1.1 什么是宏内核(Monolithic Kernel)](#1.1 什么是宏内核(Monolithic Kernel))
- [1.2 为什么 Linux 选宏内核](#1.2 为什么 Linux 选宏内核)
- [1.3 宏内核的"软化":模块化](#1.3 宏内核的"软化":模块化)
- [1.4 你的对照锚点](#1.4 你的对照锚点)
- [二、一切皆文件(Everything is a File)⭐](#二、一切皆文件(Everything is a File)⭐)
-
- [2.1 这是 Unix/Linux 的灵魂](#2.1 这是 Unix/Linux 的灵魂)
- [2.2 为什么这么设计](#2.2 为什么这么设计)
- [2.3 VFS 是实现(12 篇详讲)](#2.3 VFS 是实现(12 篇详讲))
- [2.4 "不是真文件"的例外](#2.4 "不是真文件"的例外)
- [三、机制与策略分离(Mechanism vs Policy)](#三、机制与策略分离(Mechanism vs Policy))
-
- [3.1 内核只提供机制,策略留给用户态](#3.1 内核只提供机制,策略留给用户态)
- [3.2 为什么](#3.2 为什么)
- [3.3 例外:内核也有策略](#3.3 例外:内核也有策略)
- [四、可移植性:arch 抽象层](#四、可移植性:arch 抽象层)
-
- [4.1 一套核心,多架构](#4.1 一套核心,多架构)
- [4.2 对接 RISC-V 专栏](#4.2 对接 RISC-V 专栏)
- [4.3 对接 FreeRTOS port 层](#4.3 对接 FreeRTOS port 层)
- [五、向后兼容(不破坏用户态 ABI)](#五、向后兼容(不破坏用户态 ABI))
-
- [5.1 内核 ABI 稳定承诺](#5.1 内核 ABI 稳定承诺)
- [5.2 内核内部 API 不保证稳定](#5.2 内核内部 API 不保证稳定)
- [六、惰性分配(Lazy Allocation)](#六、惰性分配(Lazy Allocation))
-
- [6.1 核心思想:用到才给](#6.1 核心思想:用到才给)
- [6.2 对照 MCU](#6.2 对照 MCU)
- [七、进程为中心(task_struct 是宇宙中心)](#七、进程为中心(task_struct 是宇宙中心))
-
- [7.1 一切以 task_struct 为单位](#7.1 一切以 task_struct 为单位)
- [7.2 进程 vs 线程(在 Linux 里是同一个东西)](#7.2 进程 vs 线程(在 Linux 里是同一个东西))
- [7.3 对照 FreeRTOS](#7.3 对照 FreeRTOS)
- [八、四大"认知冲击"(从 MCU/RTOS 转 Linux 的心理建设)](#八、四大"认知冲击"(从 MCU/RTOS 转 Linux 的心理建设))
-
- [8.1 冲击一:单任务裸机 → 多进程分时](#8.1 冲击一:单任务裸机 → 多进程分时)
- [8.2 冲击二:直接硬件 → 框架化(经五层)](#8.2 冲击二:直接硬件 → 框架化(经五层))
- [8.3 冲击三:ISR 直接做事 → 顶半部+下半部](#8.3 冲击三:ISR 直接做事 → 顶半部+下半部)
- [8.4 冲击四:一个地址空间 → 每进程独立虚拟空间](#8.4 冲击四:一个地址空间 → 每进程独立虚拟空间)
- [九、内核态 vs 用户态(特权边界)](#九、内核态 vs 用户态(特权边界))
-
- [9.1 两个特权级](#9.1 两个特权级)
- [9.2 上下文切换(特权切换)](#9.2 上下文切换(特权切换))
- [9.3 为什么分两层](#9.3 为什么分两层)
- 十、内核空间布局与源码地图
-
- [10.1 内核镜像布局](#10.1 内核镜像布局)
- [10.2 内核源码目录地图](#10.2 内核源码目录地图)
- [十一、Linux vs FreeRTOS vs RISC-V bare-metal 总对照](#十一、Linux vs FreeRTOS vs RISC-V bare-metal 总对照)
- 十二、本篇小结
- 速查表
一、宏内核 vs 微内核(第一个根本选择)
1.1 什么是宏内核(Monolithic Kernel)
Linux 是宏内核 :内核是一个巨大的程序,进程管理/内存/文件系统/驱动/网络/IPC 全在同一个内核地址空间运行,全在内核态(S 态)。
┌─────────────────────────────────┐
│ 用户态(U 模式) │ app1 app2 app3
├─────── syscall(唯一的门)─────────┤
│ 内核态(S 模式,一个地址空间) │
│ ┌──────┬──────┬──────┬───────┐ │
│ │ 进程 │ 内存 │ VFS │ 驱动 │ │ ← 全在一起,函数直接调用
│ │ 调度 │ 管理 │ │ 网络 │ │
│ └──────┴──────┴──────┴───────┘ │
└─────────────────────────────────┘
│ 系统调用(特权指令 ecall/syscall)
▼
硬件(M 模式,BootROM/SBI/固件)
对照微内核 (Mach/L4/seL4):内核只留最小功能(调度/IPC/简单内存),文件系统/驱动/网络作为独立进程跑在用户态,靠 IPC 通信。
1.2 为什么 Linux 选宏内核
| 维度 | 宏内核(Linux) | 微内核(seL4/L4) |
|---|---|---|
| 性能 | 函数直接调用,快 | IPC 消息传递,慢(跨地址空间) |
| 模块化 | 弱(全在一起) | 强(每服务独立) |
| 隔离 | 弱(驱动 bug 拖垮全核) | 强(驱动崩溃不影响内核) |
| 开发 | 一切可见,易上手 | 接口严格,开发复杂 |
| 生态 | 驱动多(厂商愿意写) | 驱动少(门槛高) |
Linux 选宏内核 = 用性能和生态换隔离性 。Linus 当年和 Tanenbaum 的著名论战(1992)就是这个:Linus 认为宏内核实用、性能好、能跑起来才是王道;Tanenbaum 认为微内核才是学术正道。30 年过去,Linux 赢了,靠的是生态不是学术。
1.3 宏内核的"软化":模块化
纯宏内核的问题------驱动全编进内核,内核巨大。Linux 的折中:内核模块(LKM),驱动可动态加载,但仍跑在内核态(不是微内核的"用户态驱动")。
嵌入式视角:模块不是微内核
你写 Linux 驱动用
.ko模块,这不是微内核 。模块加载后,代码进内核地址空间,和内核其他部分同特权同地址空间------一个模块 bug 照样 panic 全核。模块只是"运行时链接",不是"隔离" 。对照RISC-V 的.o链接进 ELF,LKM 是运行时做这事(09 篇详讲)。
1.4 你的对照锚点
| FreeRTOS | RISC-V bare-metal | Linux | |
|---|---|---|---|
| 内核形态 | 宏内核(一坨) | 你写的 App 就是"内核" | 宏内核(巨大一坨) |
| 特权层 | 无特权(全在 M) | 你在 M | 内核在 S,用户在 U |
| 模块化 | 无(LKM 概念) | 静态链接 | LKM 动态加载 |
二、一切皆文件(Everything is a File)⭐
2.1 这是 Unix/Linux 的灵魂
Linux 承袭 Unix 哲学:所有资源都用文件抽象。
| 资源 | 文件路径 | 操作 |
|---|---|---|
| 普通文件 | /home/me/a.txt |
open/read/write/close |
| 设备(字符) | /dev/ttyS0, /dev/i2c-0 |
open/read/write/ioctl |
| 设备(块) | /dev/mmcblk0 |
open/read/write |
| 管道 | pipe() 创建 | read/write |
| 套接字 | socket() 创建 | send/recv |
| 进程信息 | /proc/self/status |
read |
| 内核参数 | /proc/sys/..., /sys/... |
read/write |
| 调试信息 | /sys/kernel/debug/... |
read |
统一的接口 :open → read/write → close。不管背后是磁盘、串口、还是内核数据结构,用户态看到的都是这个流程。
2.2 为什么这么设计
- 接口统一 :学一套 API 操作所有资源。新设备驱动实现
file_operations,用户态代码不用改。 - 可组合 :shell 管道
cat file | grep x | wc -l能工作,因为都是文件读写。 - 工具复用 :
cat/echo/grep能操作任何文件类资源,不用为每资源写专用工具。
2.3 VFS 是实现(12 篇详讲)
"一切皆文件"靠 VFS(Virtual File System) 实现。VFS 定义四对象(superblock/inode/dentry/file),每个具体文件系统(ext4/proc/sysfs/设备驱动)实现这些对象的接口。用户 open("/dev/ttyS0") → VFS 路径解析 → 落到 tty 驱动的 file_operations.open。
嵌入式视角:MCU 没有"文件"这层
你裸机/FreeRTOS 访问 UART:
uart_send(0x55),直接调函数。Linux 访问 UART:open("/dev/ttyS0")→write(fd, "\x55", 1)。多了一层文件抽象,看似啰嗦,但带来 :① 用户态不用知道驱动细节;② 权限控制(文件权限);③ 可用通用工具(cat/echo)测试;④ 重定向/管道。这是 Linux 给"设备访问"加的标准化外壳。
2.4 "不是真文件"的例外
- 网络套接字:有 fd,但不是文件系统路径(bind/connect 用地址)
- 匿名管道:有 fd,无路径
- epoll/inotify:有 fd,无路径
- timerfd/eventfd/signalfd:有 fd,无路径
这些是"文件描述符(fd)"抽象的扩展------fd 是"可读写的句柄"的泛化,不一定对应磁盘文件。这是"一切皆文件"的现代演化。
三、机制与策略分离(Mechanism vs Policy)
3.1 内核只提供机制,策略留给用户态
机制(Mechanism) = "能做什么"(能力)。策略(Policy)= "怎么做"(决定)。
Linux 原则:内核实现机制,策略尽量在用户态。
| 机制(内核) | 策略(用户态) |
|---|---|
| 进程调度器(CFS/EEVDF) | 进程优先级/nice(用户设) |
| 内存分配(buddy/slab) | 分多少、何时分配(用户程序) |
| 文件系统(ext4 接口) | 挂载点/挂载选项(用户/mount) |
| 网络协议栈 | 路由/防火墙规则(iptables) |
| 设备驱动 | 用哪个设备/怎么用(应用) |
| cgroup | 资源限额(用户配) |
3.2 为什么
- 灵活性:同一个机制支持多种用法(调度器既跑桌面又跑服务器)。
- 内核精简:策略多变,放内核要重编;放用户态可热改。
- 避免争议:策略选择是"品味"问题,内核只给能力,不替你决定。
3.3 例外:内核也有策略
不是绝对。调度器的 CFS 算法本身是策略(选谁跑),但放内核(性能要求)。性能敏感的策略进内核,可配置/可变的策略留用户态。
嵌入式视角:FreeRTOS 策略更固化
FreeRTOS 调度策略(优先级抢占)写死在内核,你只能配优先级数值,不能换算法。Linux 给你 CFS/EEVDF/RT 多选,还能配调度参数。Linux 的"机制策略分离"给你更多控制权,但也更复杂。你转型时要适应"很多东西在用户态配,不是改内核"。
四、可移植性:arch 抽象层
4.1 一套核心,多架构
Linux 跑在 x86/ARM/RISC-V/MIPS/PowerPC... 几十种架构。靠 arch/ 目录隔离架构相关代码:
linux/
├── arch/
│ ├── arm/ ← ARM 32
│ ├── arm64/ ← ARM 64
│ ├── riscv/ ← RISC-V(对接你的专题)
│ ├── x86/ ← x86
│ └── ...
├── kernel/ ← 架构无关(调度/信号/进程通用)
├── mm/ ← 架构无关(内存管理通用)
├── drivers/ ← 驱动(大部分架构无关)
└── fs/ ← 文件系统(架构无关)
arch/<arch>/ 里放:启动汇编、trap entry、上下文切换、TLB 管理、原子操作实现、DMA 抽象等必须用具体 ISA 指令的代码。其余用 C 写,跨架构共享。
4.2 对接 RISC-V 专栏
arch/riscv/ 就是 \[00-RISC-V架构专题总目录\|RISC-V 专题] 讲的那些机制在 Linux 里的落地:
| RISC-V 专题概念 | Linux arch/riscv 落地 |
|---|---|
| \[04-trap 机制详解] | arch/riscv/kernel/entry.S(trap entry) |
| \[03-CSR 速查与特权架构 M-S-U] | Linux 在 S 态,用 sstatus/stvec/sepc |
| \[05-中断系统 PLIC-CLINT-AIA] | arch/riscv/kernel/irq.c + irqchip 驱动 |
| \[06-内存 PMP-MMU-RVWMO] Sv39 | arch/riscv/mm/(页表、sfence.vma) |
| \[07-启动与 bare-metal 流程] | arch/riscv/kernel/head.S(启动汇编) |
你的 RISC-V 专题是读 arch/riscv 的钥匙
你刚啃完 RISC-V 专题------trap/CSR/PLIC/Sv39/启动汇编。这些正是
arch/riscv/的全部内容 。普通 Linux 学习者卡在"arch 层看不懂",你能直接看懂。这是你的优势,学 Linux 内核比纯软件背景的人快,就快在这。
4.3 对接 FreeRTOS port 层
你深到 FreeRTOS V11.1 的 port 层------port.c/portASM.s。FreeRTOS 的 port 层 = Linux 的 arch 层,职责完全一样:隔离架构差异。区别:FreeRTOS port 小(几百行),Linux arch 大(几万行),但抽象思路同。
五、向后兼容(不破坏用户态 ABI)
5.1 内核 ABI 稳定承诺
Linux 承诺:用户态程序不会被内核升级破坏。一个 10 年前编译的二进制,在新内核上照样跑。这靠:
- syscall 编号稳定(sys_open 永远是那个号)
- syscall 参数语义稳定(不悄悄改含义)
- 数据结构 UABI 稳定 (
struct stat布局不变)
5.2 内核内部 API 不保证稳定
注意区分:
- UABI(用户态接口):稳定,不破坏
- 内核内部 API(驱动用的) :不稳定,版本间可改
你写驱动用的 register_chrdev/file_operations 等内核 API,版本升级可能改签名。这是写驱动要跟内核版本对齐的原因。
嵌入式视角:和你 ROM 固化的 ABI 稳定同构
如果做过ROM固化,可知ROM 固化函数的 ABI 不能变,调用方和固化方 -march/-mabi 必须一致。Linux 的 UABI 稳定和ROM 固化 ABI 稳定是同一个道理------接口稳定,实现可换。区别:Linux 的 UABI 跨版本跨设备,ROM ABI 跨固件版本。
六、惰性分配(Lazy Allocation)
6.1 核心思想:用到才给
Linux 大量用"惰性"------资源用到才真正分配,不用省着。
| 惰性机制 | 是什么 | 好处 |
|---|---|---|
| COW(Copy-On-Write) fork | fork 不真复制页表,父子共享,写时才复制 | fork 快,省内存 |
| Demand paging | mmap/分配不立即给物理页,访问时缺页才分配 | 启动快,省内存 |
| Lazy file mapping | mmap 文件不立即读盘,访问缺页才读 | 大文件不用全加载 |
| Lazy thread | clone 线程栈按需扩展 | 省栈空间 |
| Slab 缓存 | 对象池,分配过的不销毁,留着复用 | 快 |
6.2 对照 MCU
MCU 是"立即分配"------malloc(100) 立刻给 100 字节,fork 不存在(没进程概念)。Linux 惰性是因为有虚拟内存和 page fault 机制撑腰:可以"先承诺,后兑现",访问时缺页中断进内核补上。
缺页(page fault)是 Linux 内存管理的发动机
\[04-trap 机制详解] 学过 trap,page fault 是其中一类(mcause 13/15)。Linux 内存管理的核心机制------demand paging/COW/mmap/swap------全靠 page fault 触发 。内核:① 承诺地址(改页表标记"未分配");② 用户访问 → page fault;③ 内核分配物理页、填页表、返回重试。理解 page fault,就理解 Linux 内存管理的一半(04 篇详讲)。
七、进程为中心(task_struct 是宇宙中心)
7.1 一切以 task_struct 为单位
Linux 内核里,进程(线程)是核心数据结构 task_struct。所有子系统都围绕它:
- 调度器:选 task_struct 跑
- 内存:每个 task_struct 有
mm_struct(地址空间) - 文件:每个 task_struct 有
files_struct(打开的文件) - 信号:每个 task_struct 有信号挂起位
- 审计/cgroup/命名空间:都挂在 task_struct
7.2 进程 vs 线程(在 Linux 里是同一个东西)
Linux 不区分进程线程------都是 task_struct。
- "进程":一组共享
mm_struct的 task_struct 只有一个 - "线程":一组共享
mm_struct的 task_struct 有多个(clone 时共享 mm)
这和 Windows/传统 Unix 不同(Linux 线程叫"轻量进程")。统一抽象简化内核(03 篇详讲)。
7.3 对照 FreeRTOS
| FreeRTOS | Linux | |
|---|---|---|
| 任务单位 | TCB(小,几百字节) | task_struct(大,几 KB) |
| 任务数据 | 栈/优先级/状态 | 栈/优先级/状态 + mm + files + signals + ... |
| 进程/线程 | 只有任务 | 都是 task_struct(共享 mm 与否区分) |
嵌入式视角:task_struct 是"胖 TCB"
你熟 FreeRTOS TCB。Linux 的 task_struct 是"胖版 TCB"------多了 mm(地址空间)、files(文件表)、signals(信号)、namespace(容器)等。因为 Linux 任务要独立地址空间和文件上下文,FreeRTOS 任务全在一个地址空间共享一切。03 篇会逐字段拆 task_struct。
八、四大"认知冲击"(从 MCU/RTOS 转 Linux 的心理建设)
这是你转型最痛的四点,先打预防针:
8.1 冲击一:单任务裸机 → 多进程分时
你的惯性 :main() 一个死循环,跑完所有事,独占 CPU。
Linux 现实:你的程序只是千百个进程之一,调度器随时切走 CPU。你不能假设"我跑着没人打断我"------别的进程在跑,中断在来,内核在调度。
适应:
- 别用"独占 CPU"思维写代码(无脑忙等)
- 用阻塞 API(
read没数据会睡,不是忙等) - 共享数据要同步(别的进程/线程可能同时访问)
8.2 冲击二:直接硬件 → 框架化(经五层)
你的惯性 :写 UART 驱动,直接 *(volatile uint32_t*)UART_BASE = 0x55;。
Linux 现实 :用户态不能直接访问硬件(用户态没权限)。你要写内核驱动,经框架:
用户 write(fd, "\x55", 1)
→ VFS(sys_write)
→ 文件系统/设备层
→ 驱动的 file_operations.write
→ 你终于碰寄存器
五层抽象。看似啰嗦,但带来权限/安全/通用/可组合。
适应:接受框架开销,学会在框架里写(drivers/ 目录),不绕框架。
8.3 冲击三:ISR 直接做事 → 顶半部+下半部
你的惯性 :FreeRTOS ISR 里处理完,xQueueSendFromISR 通知任务。
Linux 现实 :中断顶半部不能睡眠、不能耗时 (关中断影响全系统)。耗时/可睡眠的活推迟到下半部(softirq/workqueue/threaded irq)。这是硬规则,违反会死机。
适应:中断驱动要分"哪些必须顶半部做(确认/拷贝数据),哪些推下半部(处理/通知)"(05 篇详讲)。
8.4 冲击四:一个地址空间 → 每进程独立虚拟空间
你的惯性:FreeRTOS 所有任务共享一个地址空间,指针随便传。
Linux 现实 :每个进程有独立虚拟地址空间,你的指针到另一个进程是无效地址。内核态地址空间全局共享,但用户态隔离。驱动在内核态,要小心用户态指针不能直接解引用(用 copy_to_user/copy_from_user)。
适应:
- 用户态↔内核态传数据用专用 API(
copy_to_user/copy_from_user) - 不要假设两个进程的指针互通
- DMA buffer 要在内核态分配/映射(04 篇详讲)
四大冲击的本质
这四个冲击,本质都是**"隔离"**带来的:Linux 要隔离进程、隔离用户/内核、隔离中断上下文、隔离地址空间------为了安全/稳定/多用户。MCU 不要隔离(单一职责),Linux 必须隔离(多用途)。理解"为什么隔离",就理解 Linux 大部分设计。
九、内核态 vs 用户态(特权边界)
9.1 两个特权级
用户态(U 模式) ← app 运行,权限受限
│ syscall(ecall/syscall 指令)
▼
内核态(S 模式) ← 内核运行,全权(除 M 模式保留)
│ SBI 调用(ecall to M)
▼
M 模式 ← SBI/OpenSBI/固件,硬件层
- 用户态:不能直接访问硬件、不能执行特权指令、不能访问内核内存。要这些,走 syscall 进内核。
- 内核态:全权访问硬件(经驱动)、内核内存、特权指令。Linux 内核在这层(RISC-V 上是 S 态,不是 M 态------M 态留给 SBI)。
9.2 上下文切换(特权切换)
每次 syscall/中断/异常,用户态↔内核态切换,要保存上下文:
- 保存用户态寄存器(到内核栈)
- 切到内核栈
- 切特权级(S→U 或 U→S)
- 执行内核代码
- 返回时恢复
这正是你 \[04-trap 机制详解] 学的 trap 机制,Linux 在 arch/riscv/kernel/entry.S 实现。
9.3 为什么分两层
- 安全:恶意/bug 程序不能直接搞挂系统
- 多用户:进程隔离,互不干扰
- 资源管理:内核统一管硬件,仲裁访问
嵌入式视角:RISC-V 专题的 S/U 层落地
\[03-CSR 速查与特权架构 M-S-U] 讲过 M/S/U 金字塔。Linux 内核在 S 态 ,不在 M 态------M 态给 SBI(OpenSBI)做最底层时钟/复位/console。\[04-trap 机制详解] trap entry,在 Linux 里就是
arch/riscv/kernel/entry.S,处理 U→S 的 syscall 和中断。学的 RISC-V S 态机制,就是 Linux 内核运行的环境。
十、内核空间布局与源码地图
10.1 内核镜像布局
内核镜像(物理/虚拟):
┌──────────────┐ 高地址
│ _end │
├──────────────┤
│ .bss │ 未初始化全局(启动清零)
├──────────────┤
│ .data │ 已初始化全局
├──────────────┤
│ .rodata │ 只读(常量/页表)
├──────────────┤
│ .text │ 代码
├──────────────┤
│ _stext │
├──────────────┤
│ (modules 区) │ LKM 加载区(独立虚拟区)
└──────────────┘ 低地址
和 \[09-工具链深挖 relaxation-ELF] 学的 ELF 段一致------内核也是 ELF。区别:内核有特殊段(.init.text 启动后丢弃、.percpu 每 CPU 数据、__ex_table 异常表)。
10.2 内核源码目录地图
linux/
├── arch/ 架构相关(riscv/arm64/x86...) ← 你能看懂
├── kernel/ 核心子系统(调度/信号/进程)
├── mm/ 内存管理
├── fs/ 文件系统(VFS + 各 fs)
├── drivers/ 驱动(大头,占代码量 70%+)
├── net/ 网络协议栈
├── ipc/ 进程间通信
├── security/ 安全框架(selinux/capabilities)
├── block/ 块 IO 层
├── lib/ 内核通用库
├── init/ 启动(start_kernel)
├── include/ 头文件
├── scripts/ kbuild 脚本
└── Makefile, Kconfig 构建系统
读源码的入口顺序
别从
init/main.c的start_kernel一行行读(会迷路)。建议:
- 先读本专题 16 篇,建模块地图
- 读
arch/riscv/kernel/head.S(启动,你能懂)- 读
init/main.c的start_kernel(看子系统初始化顺序)- 按兴趣读子模块(从
kernel/开始)- 读驱动从
drivers/找一个简单的(misc目录)
十一、Linux vs FreeRTOS vs RISC-V bare-metal 总对照
三大对照锚点的全景表:
| 维度 | FreeRTOS | RISC-V bare-metal | Linux |
|---|---|---|---|
| 内核形态 | 宏(小) | 你的 App | 宏(大) |
| 特权 | 无(M 全权) | 你在 M | S(内核)+ U(用户) |
| 任务单位 | TCB | 无(单 main) | task_struct |
| 调度 | 优先级抢占 | 无/你写 | CFS/EEVDF 公平 |
| 地址空间 | 一个共享 | 一个物理 | 每进程虚拟 |
| 中断 | ISR+FromISR | 你写 trap | 顶半部+下半部 |
| 文件系统 | 无 | 无 | VFS(一切皆文件) |
| 设备访问 | 直接函数 | 直接寄存器 | 框架化(经 VFS) |
| 驱动 | 函数集合 | 你写 | 模块+框架 |
| 同步 | 信号量/互斥 | 关中断/原子 | spinlock/mutex/RCU |
| 启动 | reset→main | BootROM→BL→_start | BootROM→U-Boot→start_kernel→init |
| 内存分配 | heap策略(1~5) | 静态/你写 | buddy/slab/kmalloc |
| tick | mtimecmp | 你配 | hrtimer+tick+nohz |
这张表是你的"翻译字典"
学 Linux 每个概念,回这表查 FreeRTOS/RISC-V 对应物。你的知识不是白学,是 Linux 的子集和前身。带着这表读后面 15 篇,速度翻倍。
十二、本篇小结
- 宏内核:Linux 是一坨大内核,全在 S 态,函数直接调用,性能好但隔离弱;LKM 是软化不是微内核
- 一切皆文件:设备/管道/socket/proc 都是文件,VFS 统一 open/read/write 接口
- 机制与策略分离:内核给机制(调度器/分配器),策略留用户态(优先级/用量);性能敏感策略例外进内核
- 可移植性:arch/ 隔离架构差异,你 RISC-V 专题正是读 arch/riscv 的钥匙
- 向后兼容:UABI 稳定(用户程序不破坏),内核内部 API 不稳定(驱动要跟版本)
- 惰性分配:COW fork/demand paging/mmap,全靠 page fault 发动机
- 进程为中心:task_struct 是宇宙中心,进程线程统一抽象
- 四大冲击:单任务→多进程分时、直接硬件→框架化、ISR→顶半部+下半部、一地址空间→每进程虚拟
- 特权边界:内核 S 态,用户 U 态,syscall 是唯一的门
- 源码地图:arch/(架构) + kernel/mm/fs/drivers/net(子系统)
速查表
| 想干啥 | 看哪 |
|---|---|
| 理解 Linux 为什么这么设计 | 本篇 |
| 找架构相关代码 | arch// |
| 找启动代码 | arch//kernel/head.S + init/main.c |
| 找调度器 | kernel/sched/ |
| 找内存管理 | mm/ |
| 找驱动框架 | drivers/base/ |
| 找一个驱动示例 | drivers/misc/ 或 drivers/char/ |
| 用户态访问设备 | open("/dev/xxx") → read/write/ioctl |
| 用户态↔内核态传数据 | copy_to_user / copy_from_user |
| 找 RISC-V 专题对应 | arch/riscv/ 全目录 |
💡技术之路漫漫,分享是为了更好地交流。如果本文的内容对你有启发,希望能得到你的 点赞 👍 和 收藏 ⭐。
如果你在调试过程中遇到了其他问题,欢迎在 评论区 💬 留言,我们一起探讨。也欢迎 关注 👀 我,一起交流底层开发的那些事儿。