Linux 内核最早是在 1991 年由芬兰大学生林纳斯·托瓦兹为自己的个人电脑开发的,并在 GNU 通用公共许可证第 2 版(也包含了其他兼容许可证)之下发布的一种开源的类 Unix 操作系统宏内核。
注意,我们通常说的 Linux 系统是 Linux Kernel + 其他组件 形成的整体。在早期,Linux Kernel 本身就叫 linux,而如今,Linux 这个名词更多是指使用 Linux Kernel 的 Linux 系统,内核则用 Linux Kernel 来表示。
在上世纪 60 年代,Unix 开发者简单地称他们的内核为 “unix”,所以,Linux 在上世纪 90 年代诞生后,Linus 开始称他们的内核为 “Linux”。
从技术上说,Linux 只是一个符合 POSIX 标准的内核。它提供了一套应用程序接口(API),通过这些 API,用户程序能与内核及硬件交互。硬件则在文件层次结构中表示,用户应用程序通过 /dev
或 /sys
目录中的条目与设备驱动程序进行交互。
Linux 最初是为基于 32 位 x86 架构的 PC 开发的。如今,它已经可以工作在了 Compaq Alpha AXP、Sun SPARC、Motorola 68000、PowerPC、ARM、Hitachi SuperH、IBM S/390、MIPS、HP PA-RISC,Intel IA-64 等众多平台之上。
架构
内核架构主要有 宏内核(Monolithic Kernel)、微内核(Micro kernel)和混合内核(Hybrid kernel) 三种。Linux 系统的 Kernel 属于宏内核,而 Windows 系统的内核 Windows NT 和 macOS 的内核 XNU 都属于混合内核。
- 宏内核: 整个操作系统在内核模式下以单个程序运行。用户服务和内核服务在同一地址空间中实现。
- 微内核: 将用户服务保存在用户地址空间中,并且内核服务保存在内核地址空间下
- 混合内核: 混合核心的基本设计理念是以微内核架构来设计操作系统核心,但在实现上则采用宏内核的作法。
Linux Kernel 将功能划分为了各种子系统,子系统之间相对独立。其中,最为核心的应该就是下面的 5 个子系统,这 5 大子系统也是在众多书籍中的常客。但是,随着 Linux Kernel 的不断发展,新的子系统也在不断出现。
- Process Scheduler:也称作进程管理、进程调度。负责管理 CPU 资源,以便让各个进程可以以尽量公平的方式访问 CPU。
- Memory Manager:内存管理。负责管理 Memory(内存)资源,以便让各个进程可以安全地共享机器的内存资源。另外,内存管理会提供虚拟内存的机制,该机制可以让进程使用多于系统可用 Memory 的内存,不用的内存会通过文件系统保存在外部非易失存储器中,需要使用的时候,再取回到内存中。
- VFS(Virtual File System):虚拟文件系统。Linux 内核将不同功能的外部设备,例如 Disk 设备(硬盘、磁盘、NAND Flash、Nor Flash等)、输入输出设备、显示设备等等,抽象为可以通过统一的文件操作接口(open、close、read、write等)来访问。这就是 Linux 系统“一切皆是文件”的体现(其实 Linux 做的并不彻底,因为 CPU、内存、网络等还不是文件,如果真的需要一切皆是文件,还得看贝尔实验室正在开发的 "Plan 9” 的)。
- Network:网络子系统。负责管理系统的网络设备,并实现多种多样的网络标准。
- IPC(Inter-Process Communication):进程间通信。IPC 不管理任何的硬件,它主要负责 Linux 系统中进程之间的通信。
Linux Kernel 是一个具有模块化设计的多任务宏内核。大多数设备驱动程序和内核扩展在内核空间中运行(在许多 CPU 架构中为 Ring 0),可以完全访问硬件。当然也有些例外,例如,Linux 的 GUI 框架 X Window System 和 Wayland 就不在内核空间。
与标准的宏内核不同,Linux Kernel 的设备驱动程序可以很容易地配置为模块,并在系统运行时加载或卸载,还可以在某些条件下被抢占,以便正确地处理硬件中断并更好地支持对称多处理(Symmetric Multiprocessing,SMP)。
- SMP 是一种多核处理器架构,在对称多处理架构下,每个处理器的地位都是平等的,对资源的使用权限相同
- AMP(Asymmetric Multiprocessing,非对称多处理)是指多个不对称处理器的情况,通常只有一个一个处理为主,运行大部分任务,其他处理器辅助运行其他任务
Linux API/ABI
Linux 内核开发、GNU C 函数库和相关的实用工具致力于遵循 POSIX 和单一 UNIX 规范。Linux API 和 Linux ABI 是保证 Linux 兼容性的一个重要基础,也是防止 Linux 系统分裂化的一个重要措施。linux 基金会官网 https://refspecs.linuxfoundation.org/ 上列出了 linux 的各种规范。
- 向后二进制兼容性(Backward binary compatibility,即 ABI 兼容性)保证使用旧版本库的程序在库升级为新版后仍可以正常运行,而无需重新编译。
- 向后源代码兼容性(Backward source compatibility,即 API 兼容性)保证旧程序更换为新版本的库时仍然可以成功地重新编译。
POSIX(Portable Operating System Interface for Computing Systems)是由 IEEE 和 ISO/IEC 开发的基于现有的 Unix 实践和经验标准系统。它描述了操作系统的调用服务接口,用于保证编制的应用程序可以在源代码一级上在多种操作系统上移植运行。
官网:https://pubs.opengroup.org/onlinepubs/9699919799/
单一 UNIX 规范(Single UNIX Specification,SUS)是一套 UNIX 系统的统一规格书。 它扩充了 POSIX 标准,定义了标准 UNIX 操作系统。 由 IEEE 与 The Open Group 所提出,目前由 Austin Group 负责维持。
- 如果操作系统被提交给 The Open Group 进行认证,并通过了一致性测试,则认为它符合 UNIX 标准
- 很少有基于 BSD 和 Linux 的操作系统被提交以符合单一 UNIX 规范
Linux API
Linux API 指的是内核到用户空间的 Linux 应用编程使用的接口(Application Programming Interface,API)。这些 API 允许用户空间中的程序访问 Linux 内核的系统资源和服务。它由 Linux 内核的系统调用接口和 GNU C 库(GLIBC)中的各种接口组成。
- 系统调用接口: 指内核中所有已实现和可用的系统调用的集合。各种子系统,例如直接渲染管理器(DRM)定义自己的系统调用。
- C 标准库: 是围绕 Linux 内核的系统调用的包装器。多数情况下都是使用 C 库接口间接使用系统调用。
伪文件系统(例如,sysfs 和 procfs 文件系统)和特殊文件(例如, /dev/random
/dev/sda
, /dev/tty
等)构成代表硬件和特定数据结构的一类特殊的接口。
Kernel API
Kernel API 指的是内核内部各子系统之间使用(Linux 内核编程)的接口。Linux 内核编程与 Linux 应用编程有很大的不同。内核是一个独立的实体,不能使用用户空间中的库。因此,通常的用户空间函数(printf、malloc、free、open、read、write、memcpy、strcpy 等)将不能再使用。内核编程是基于一种全新的、独立的 API 进行的,与用户空间 API 无关。
有些内核内符号集也被公开(
EXPORT_SYMBOL()
和EXPORT_SYMBOL_GPL()
)给动态加载的模块(例如,按需加载的设备驱动程序)
根据 Kernel 官方说明,Kernel API 的稳定性不能得到保证,因此,设备驱动程序代码以及任何其他内核子系统的代码都必须随着内核的发展而不断更新。任何进行 API 更改的开发人员都需要修复由于他们的更改而损坏的任何代码。
Linux ABI
Linux ABI 指的是内核到用户空间的 ABI(Application Binary Interface )。二进制可移植性将保证任何程序在符合标准的给定硬件平台上一旦编译通过,可以在符合同样标准的任何其他硬件平台上以编译后的形式运行。现有唯一的二进制兼容标准是 Linux 标准规范(Linux Standard Base,LSB)。
ABI 都是被绑定到指令集的
Linux 标准规范(Linux Standard Base,LSB)基于 POSIX 规范,单一 UNIX 规范和其他开放标准,并在几个领域进行了扩展。LSB 和 POSIX 标准之间存在一些冲突。尽管 LSB 被普遍接受,但很少有 Linux 发行版真正通过 LSB 兼容认证。LSB 定义的内容包括:
- 标准库
- 一系列命令和工具(在 POSIX 基础上进行了扩展)
- 文件系统层级结构
- 运行级别
- 打印系统
- 包含假脱机(spoolers),诸如 CPUS 和类似 Foomatic 这样的工具
- 若干对 X Window 系统的扩展
LSB 官网:https://refspecs.linuxfoundation.org/lsb.shtml
文件层次结构
FHS(Filesystem Hierarchy Standard,文件系统层次结构标准)是多数 Linux 发行版采用这种文件组织形式,FHS 定义了系统中每个区域的用途、所需要的最小构成的文件和目录同时还给出了例外处理与矛盾处理。
FHS 是根据以往无数 Linux 用户和开发者的经验总结出来的,FHS 是依据文件系统使用的频繁与否以及是否允许用户随意改动而持续更新的。FHS 由 Linux 基金会维护,最新版本是 2015 年 6 月 3 日发布的 3.0,官方网站:https://refspecs.linuxfoundation.org/fhs.shtml。
大多数 Linux 发行版都宣称自己遵循 FHS,但也不是 100%,有些目录被合并。
FHS 定义了两层规范,第一层是 /
下面的各个目录应该要放什么文件数据,例如,/etc
应该要放置设置文件,/bin
与 /sbin
则应该要放置可执行文件等等。 第二层则是针对 /usr
及 /var
这两个目录的子目录来定义。例如 /var/log
放置系统登录文件、/usr/share
放置共享数据等等。
-
/bin:Binaries 的缩写,存放一些可以被 root 与一般用户所使用的可执行程序(也可以是一些符号连接),例如
cat
、chmod
、chown
、date
、mv
、mkdir
、cp
、bash
等常用的指令。- Ubuntu 中,它是一个指向
/usr/bin
的硬链接 - FHS 规定,该目下不能有子目录;且命令
[
和test
必须同时被放在/bin
和/usr/bin
- Ubuntu 中,它是一个指向
-
/boot:放置开机会使用到的文件(Kernel 在执行用户空间程序之前使用的文件),包括 Linux 核心文件以及开机菜单、磁盘映射等等。注意,与启动无关的配置文件不应该放在该目录下(应该放到
/etc
下)且与引导相关的可执行程序应该放到/sbin
下。操作系统内核必须存在
/
目录或者/boot
目录 -
/dev:在 Linux 系统上,任何设备与周边设备都是以文件的型态存在于这个目录当中的。 通过存取这个目录下面的某个文件,就等于存取某个设备了。
-
/etc:系统主要的配置文件几乎都放置在这个目录内,例如人员的帐号密码档、各种服务的启始档等等。一般来说,这个目录下的各文件属性是可以让一般使用者查阅的, 但是只有 root 有权修改。注意,该目录下不要存放可执行程序(可以有少许脚本)。
- /etc/opt:这个目录中存放放置在
/opt
中的软件的相关配置文件 - /etc/sgml:与 SGML 格式有关的各项配置文件
- /etc/X11:与 X Window 有关的各种配置文件都在这里,例如, X Server 的配置文件 xorg.conf。
- /etc/xml:与 XML 格式有关的各项配置文件
- /etc/opt:这个目录中存放放置在
-
/lib:系统的函数库非常的多,而
/lib
放置的则是在开机时会用到的函数库, 以及在/bin
或/sbin
下面的可执行程序会调用的函数库。- Ubuntu 中,它是一个指向
/usr/bin
的硬链接 - 与不同架构对应,lib 通常分为 lib32、lib64 等
- /lib/modules/:主要放置可抽换式的核心相关模块(驱动程序)。
- Ubuntu 中,它是一个指向
-
/media:media 是“媒体”的英文,用于放置可移除的设备, 例如,软盘、光盘、DVD 等等设备都暂时挂载于此。常见的文件名有:
/media/floppy
、/media/cdrom
等等。 -
/mnt:暂时挂载的某些其他的设备一般放置到这个目录中。在古早时候,这个目录的用途与
/media
相同,有了/media
之后,这个目录就用来暂时挂载用了。 -
/opt:用于存放那些第三方非系统软件。这里的软件通常都是静态程序(或者包含了自身需要的各种依赖文件)。常见的就是那些 GUI 软件,例如那些基于 KDE 的 GUI 程序。
在以前的 Linux 系统中,经常是放置在
/usr/local
目录下! -
/run:早期的 FHS 规定系统开机后所产生的各项信息应该要放置到
/var/run
目录下,新版的 FHS 则规范到/run
下面。 由于/run
可以使用内存来仿真,因此性能上会好很多! -
/sbin:System binaries 的缩写。Linux 有非常多指令是用来设置系统环境的,这些指令只有 root 才能够利用来“设置”系统,其他使用者最多只能用来“查询”而已。 放在
/sbin
下面的程序为开机过程中所需要的,里面包括了开机、修复、还原系统所需要的指令。 常见的指令包括:fdisk
、fsck
、ifconfig
、mkfs
等等。- Ubuntu 中,它是一个指向
/usr/sbin
的硬链接 - 该目录必须没有子目录。这里的系统工具主要指的生成系统本身时带有的那些程序,用户安装的系统程序位于
/usr/sbin
- Ubuntu 中,它是一个指向
-
/srv:可以视为 service 的缩写,是一些网络服务启动之后,这些服务所需要取用的数据目录。 常见的服务例如 WWW、FTP 等等。例如,WWW 服务器需要的网页数据就可以放置在
/srv/www/
里面 -
/tmp:这是让一般使用者或者是正在执行的程序暂时放置文件的地方。 这个目录是任何人都能够存取的,重要数据不可放置在此目录!
FHS 甚至建议在开机时,应该要将
/tmp
下的数据都删除。 -
/usr:是 Unix Software Resource 的缩写, 也就是 Unix 操作系统软件资源所放置的目录。FHS 建议所有软件开发者,应该将他们的数据合理的分别放置到这个目录下的次目录,而不要自行创建该软件自己独立的目录。
-
/usr/bin:非必要的命令二进制文件(在单用户模式下不需要);面向所有用户。
-
/usr/include:各种标准的头文件
-
/usr/lib:
/usr/bin
和/usr/sbin
中的可执行程序使用的库文件。与不同架构对应,lib 通常分为 lib32、lib64 等
-
/usr/local:特定于本主机的本地数据的三级层次结构,通常具有进一步的子目录(例如,bin,lib,Share)。那些使用源码方式安装(make)的软件通常就放到这个目录下。
-
/usr/sbin:特定于本主机的系统二进制文件(例如,各种网络服务的守护进程,管理员工具)。
-
/usr/share:与体系结构无关的(共享)数据。
-
/usr/src:该 Linux 发行版使用的 Kernel 源代码
-
-
/var:主要针对常态性变动的文件,包括高速缓存(cache)、登录文件(log file)以及某些软件运行所产生的文件, 包括程序文件(lock file、run file),或者例如 MySQL 数据库的文件等等。
- /var/cache:应用程序缓存数据。此类数据是由于耗时的 I/O 或计算而在本地生成的。应用程序必须能够重新生成或还原数据。可以删除缓存的文件而不会丢失数据。
- /var/lib:状态信息。程序在运行时修改的持久性数据(例如,数据库、打包系统元数据等)
- /var/lock:锁定文件。跟踪当前正在使用的资源的文件。
- /var/log:日志文件。里面有各种日志。
- /var/mail:邮箱文件。在某些发行版中,这些文件可能位于已弃用的
/var/spool/mail
中 - /var/opt:存储在
/opt
中的附加程序包中的变量数据。 - /var/run:运行时变量数据。此目录包含自启动系统以来描述系统的系统信息数据。在 FHS 3.0 中,
/var/run
被/run
取代,但为了向后兼容,系统应该继续提供/var/run
目录或者提供从/var/run
到/run
的符号链接。 - /var/tmp:在重新启动之间要保留的临时文件
-
/home:这是系统默认的使用者主文件夹(home directory)。新增一个一般使用者帐号时, 默认的使用者主文件夹都会规范到这里来。
通常使用
~
表示。 -
/root:系统管理员(root)的主文件夹。之所以放在这里,是因为如果进入单人维护模式而仅挂载根目录时, 该目录就能够拥有 root 的主文件夹,所以我们会希望 root 的主文件夹与根目录放置在同一个分区中。
-
/lost+found:这个目录是使用标准的 ext2/ext3/ext4 文件系统格式才会产生的一个目录,目的在于当文件系统发生错误时, 将一些遗失的片段放置到这个目录下。如果使用的是 xfs 文件系统的话,就不会存在这个目录了!
-
/proc:这个目录本身是一个虚拟文件系统(virtual filesystem),他放置的数据都是在内存当中, 例如系统核心、行程信息(process)、周边设备的状态及网络状态等等。因为这个目录下的数据都是在内存当中, 所以本身不占任何硬盘空间!比较重要的文件例如:
/proc/cpuinfo
、/proc/dma
、/proc/interrupts
、/proc/ioports
、/proc/net/*
等等。 -
/sys:这个目录其实跟
/proc
非常类似,也是一个虚拟的文件系统,主要也是记录核心与系统硬件信息较相关的信息。 包括目前已载入的核心模块与核心侦测到的硬件设备信息等等。这个目录同样不占硬盘容量。
Kernel 源码文件
Linux 内核源码的结构是由目录和子目录组成的,称为内核树。如今,Kernel 源码每天都有大量变更,最新的长期支持稳定分支 5.15.51 版本有 7 万多个文件,近 3000 万行代码。
-
arch:即 architecture 的缩写,用于存放不同 CPU 体系架构的代码。每种 CPU 体系结构都放到对应的子目录中。官方对于各种架构的说明文档:https://www.kernel.org/doc/html/latest/arch.html。
-
alpha:原名 Alpha AXP,是由数字设备公司(DEC)开发的 64 位精简指令集计算机(RISC)指令集架构(ISA)。
-
arc:最初由 ARC International 设计的一系列 32 位和 64 位精简指令集计算机(RISC)中央处理器(CPU),采用 16/32 位 ARCompact 指令集架构 (ISA)。
2009 年,ARC International 被 Virage Logic 收购。2010 年,Virage 被 Synopsys 收购,ARC 处理器成为 Synopsys DesignWare 系列的一部分
-
arm:32 位 ARM IP 系列
-
arm64:64 位 ARM IP 系列,ARMv8 开始支持 64 位架构。
-
csky:中天微 IP 系。2018 年 4 月 20 日,中天微被阿里巴巴集团全资收购。国内芯片如 方寸微电子的 T6x0 系列。
-
hexagon:高通公司一系列数字信号处理器(DSP)产品的品牌名字,也被称为 QDSP6。每个版本的 Hexagon 都有一个指令集和一个微架构。主要用于高通骁龙芯片,例如智能手机,汽车,可穿戴设备和其他移动设备,也用于蜂窝电话网络的组件。
-
ia64:Intel 安腾(itanium architecture)系列 CPU,由英特尔与惠普共同开发,与 x86 及 x86-64 并不兼容,目前基本已经死的差不多了。
Linus Torvalds 曾在一篇代码评论中透露,计划移除对 Intel 安腾处理器的支持。
-
m68k:摩托罗拉的 68000 系列 CPU,是一系列 32 位复杂指令集计算机 (CISC) 微处理器。上世纪 80 年代是英特尔 x86 微处理器的主要竞争对手。虽然没有现代台式计算机基于 680x0 系列的处理器,但衍生处理器仍然广泛用于嵌入式系统。
-
microblaze:MicroBlaze 嵌入式软核是一个被 Xilinx 公司优化过的可以嵌入在 FPGA 中的 RISC 处理器软核。
MicroBlaze Soft Processor Core
-
mips:MIPS (Microprocessor without Interlocked Pipelined Stages) 架构的精简指令集计算机 (RISC) 微处理器。MIPS 架构是由 MIPS Technologies 开发的,除了有自己的芯片,还卖 IP 供第三方开发芯片。
2021 年 3 月,Wave Computing 宣布 MIPS 架构的开发已经停止。该公司已加入 RISC-V 基金会,未来的处理器设计将基于 RISC-V 架构。
-
nios2:Altera 推出的 Nios II 系列 32 位 RISC 嵌入式处理器。主要用于 FPGA,与 MicroBlaze 竞争。
-
openrisc:OpenCores 组织提供的基于 GPL 协议的开放源代码的 RISC(精简指令集计算机)处理器。
目前国内已有基于 OR1200 核的 SOC 产品,比如,华视奇半导体有限公司推出的 Vivace Semiconductor 多媒体处理芯片
-
parisc:由惠普开发的指令集架构(ISA),其中 PA 代表 Precision Architecture。该设计也称为惠普精密架构的 HP / PA。PA-RISC 已被由惠普和英特尔联合开发的 Itanium(最初是 IA-64)ISA 取代
-
powerpc:1991 年 Apple-IBM-Motorola 联盟创建的简化指令集计算机(RISC)指令集架构(ISA),自2006年以来一直被命名为Power ISA。
-
riscv:一个基于精简指令集(RISC)原则的开源指令集架构(ISA),RISC-V 目前比较火,很多公司都在设计 RISC-V 架构的芯片。
-
s390:IBM System/390 32 位架构指令集,通常 用 s390x 表示 64 位 z/架构
-
sh:SuperH 是 90 年代早期由日立开始开发,是一种性价比、体积小、功耗低的32位、64位的RISC嵌入式微处理器
-
sparc:1987 年,SUN 公司开发的 RISC 微处理器
-
um:User-mode Linux (UML) 是 Linux 内核到其自己的系统调用接口的体系结构端口,它使多个基于 Linux 内核的虚拟操作系统(称为来宾)能够在普通 Linux 系统(称为主机)中作为应用程序运行。
-
x86:x86 架构系列
-
xtensa:Tensilica 公司的 IP,主要领域是 HiFi 音频、 语音及视觉DSP。2013年, 被 Cadence Design Systems 收购并成为的一个部门。
这些 CPU 架构子目录中,又进一步分解为下一级子目录。其中就有些功能相似的同名目录:
-
boot: 包含了系统启动的相关信息
- dts:设备树
-
configs:支持的芯片的配置文件
-
include:特定于架构的对外提供的接口
- asm:特定于架构的内核头文件(Kernel API,kapi)。可以理解为这些是内核的私有头文件。
- uapi:特定于架构的用户态头文件(Userspace API,uapi)。
- 在内核安装之后,uapi 包含文件就变成了顶级的
/usr/include/linux/*
文件。 - Kernel 3.5 版本时,David Howells 提出将用户态 API 单独存放,以解决头文件递归引用的问题。并在 3.7 版本被合并到 Mainline 仓库。
- 在内核安装之后,uapi 包含文件就变成了顶级的
-
kernel: 目录包含了中断和 SMP 等信息
-
lib:特定于架构的共用库函数
-
mm:架构 CPU 内存(含 Cache)操作的相关代码
-
-
block:该目录下放的是一些 linux 存储体系中关于块设备管理的代码。在 linux 中 block 表示块设备(以块(多个字节组成的整体,类似于扇区)为单位来整体访问),例如 SD 卡、iNand、Nand、硬盘等都是块设备。几乎可以认为块设备就是存储设备。
最初 block 层代码一部分位于 drivers 目录,一部分位于 fs 目录。从 2.6.15 开始,block 层的核心代码就被提取出来放在顶层的 block 目录中。 -
certs:存储了认证和签名相关代码。证书和签名文件用于给模块签名,并允许内核加载签名模块,有助于防止恶意代码与内核模块一起运行。
-
crypto:该目录下是 Kernel 实现的一套通用 Cryptographic 算法框架,是一个独立的子系统(Cryptographic API),目前,由 Herbert Xu 维护。它实现了对算法的统一管理,并提供出统一的数据处理接口给其他子系统使用。
-
Documentation:这个目录下是 Kernel 的文档,它使用的是 Sphinx 搭建的文档系统。Sphinx 文档系统可以生成 html、pdf 等格式。Kernel 文档在线托管地址是:https://docs.kernel.org/,在线版文档就是使用 Sphinx 基于该目录下的文档源码文件生成的 html 格式的文档,两者内容并没有区别。
Sphinx 是基于 Python 的,使用的是 reStructuredText 语言格式,文件扩展名通常是 .rst。Sphinx 文档系统使用 make 命令来生成发布的文档,在 Documentation 下执行make htmldocs
命令,就会生成一个 output 的目录,其中就包含了生成的文档。- Kernel 源码根目录的 Makefile 也有生成文档的目标,它会直接调用
Documentation/Makefile
文件 - 依赖工具: sudo apt install python3-pip 、sudo pip install -U Sphinx sphinx_rtd_theme graphviz
- Kernel 源码根目录的 Makefile 也有生成文档的目标,它会直接调用
-
drivers:该目录中是系统中所有的设备驱动程序。它又进一步根据设备类型划分成几类设备驱动,每一种有对应的子目录,如声卡的驱动对应于
drivers/sound
;block 下为块设备驱动程序。 -
fs:fs 就是 file system,该目录中是虚拟文件系统(VFS)和各个不同文件系统的代码所在的目录。其中每个逻辑文件系统 , 都在 fs 目录下有对应的目录 , 如 ext2 , ext3 , ext4 , fat , nfs 等
-
include:该目录包括编译核心所需要的大部分头文件,例如与平台无关的头文件在 include/linux 子目录下,与 intel cpu 相关的头文件在 include/asm-i386 子目录下,而 include/scsi 目录则是有关 scsi 设备的头文件目录。每种 CPU 架构特有的一些头文件则位于 arch 目录具体架构的 include 目录下(例如,
arch/arm/include
)。- uapi:共用的用户态头文件。
- 在内核安装之后,uapi 包含文件就变成了顶级的
/usr/include/linux/*
文件。 - Kernel 3.5 版本时,David Howells 提出将用户态 API 单独存放,以解决头文件递归引用的问题。并在 3.7 版本被合并到 Mainline 仓库。
- 在内核安装之后,uapi 包含文件就变成了顶级的
- uapi:共用的用户态头文件。
-
init:init是初始化的意思,这个目录下的代码就是linux内核启动时初始化内核的代码。
-
ipc:ipc就是inter process commuication,进程间通信,里面都是linux支持的IPC的代码实现
-
kernel:kernel 就是内核,就是linux内核,所以这个文件夹下放的就是内核本身需要的一些代码文件
-
lib:该目录下包含一些与架构无关的公用的函数(例如,排序、校验和、压缩和解压缩、位图操作等),以供内核的其他模块调用。与处理器结构相关的库代码(例如,strlen、memcpy 等)被放在
arch/*/lib/
目录下。
注意这里的库函数和 C 语言的库函数不一样的。在内核编程中是不能用 C 语言标准库函数,这里的 lib目录下的库函数就是用来替代那些标准库函数的。例如,在内核中要打印信息时不能用 printf,而要用 printk,这个 printk 就在 lib 目录下。 -
LICENSES:该目下存放了 Kernel 所遵循的许可证原始文件。我们都知道,Linux Kernel 是基于 GPLv2 许可证进行开源的。GPLv2 许可证是涵盖整个内核分发的许可证,但是具体到某个源码文件时,可以有不同的许可证。除此之外,个人文件可以在双重许可下提供。但是,一个前提是这些不同的的许可证必须兼容 GPLv2。
一个例外就是系统调用:编写用户空间程序时肯定得包含 Kernel 的源文件,根据 GPLv2 传染性意味着别人的用户程序也得开源,显然不合适。为此,在LICENSES/exceptions/Linux-syscall-note
中显式描述了这个情况。所以,Linux Kernel 的许可证准确的应该叫 SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note 才更合适。https://docs.kernel.org/process/license-rules.html
在 Kernel 中,源码文件的许可方式是根据文件类型的不同,在文件的开头以注释的形式显示增加
SPDX-License-Identifier: GPL-2.0-only
。Linux Kernel 要求在所有源文件中提供精确的 SPDX 标识符且标识的许可证必须是在 LICENSES 目录下已经存在的。
SPDX 许可证标识符是计算机可解析的,是贡献文件内容所依据的许可证的精确简写。SPDX 许可证标识符由 Linux 基金会的 SPDX 工作组管理,并已得到整个行业的合作伙伴、工具供应商和法律团队的同意。有关详细信息参阅 https://spdx.org/。 -
mm: memory management,内存管理,linux 的内存管理代码都在这里
-
net:该目录下是网络相关的代码,譬如TCP/IP协议栈等都在这里。
-
samples:示例
-
scripts:这个目录下是一些开发 Kernel 本身使用的脚本文件,linux 内核工作时是不会使用的。主要是用来辅助对 linux 内核进行开发(配置、编译等)。
-
security:安全相关的代码。
-
sound:音频处理相关的。
-
tools:linux 中用到的一些有用工具
-
usr:目录下是 initramfs 相关的,和 linux 内核的启动有关
-
virt:这个目录下是 KVM (Kernel Virtual Machine) 管理程序的相关代码
-
.clang-format:
.clang-format
是 LLVM 提供的针对 C/C++ 代码的格式化工具clang-format
的配置文件,包含了一些适用于 Kernel 内核编码风格的clang-format
的选项。当我们在 Kernel 源码根目录下使用clang-format
时,就会自动加载该配置文件中的配置项。.clang-format
中配置的代码风格如下所示:
.clang-format
中的配置只是尽可能多的去符合 Kernel 的编码风格。当前的 Kernel 的代码中,很多代码格式都不符合.clang-format
中配置的要求(上图中黄色表示不符合的提示)。并且,某些子系统的代码风格本身就与整体 Kernel 代码风格也存在差异。- Linux kernel coding style
clang-format
在主流 Linux 发行版中都有提供,可以非常方便的进行安装。例如,Ubuntu 中sudo apt install clang-format
-
.cocciconfig:
.cocciconfig
是 Linux 下的一个可定制程度很高的静态代码分析工具 Coccinelle 的配置文件,包含对 Coccinelle 的配置参数。在 Kernel 源码的 script 目录下提供了一个脚本script/coccicheck
供开发者使用 Coccinelle 来检测 kernel 代码。此外,根目录的 Makefile 中也专门创建了一个 coccicheck 目标。因此,可以直接使用make coccicheck
。
Coccinelle 运行依赖Spatch
程序 和 Semantic Patch Language 文件(扩展名*.cocci
文件)。当我们执行script/coccicheck
时,就会调用 Spatch 使用script/coccinelle/xxx/.cocci
语法文件来分析代码,每一个.cocci
都是一个类型的错误检测。- Linux Kernel 介绍文档:https://docs.kernel.org/dev-tools/coccinelle.html
- 官网:coccinelle.lip6.fr
- 源码:https://github.com/coccinelle/coccinelle
- 主流 Linux 发行版都会提供该工具。例如,Ubuntu:
sudo apt install coccinelle
-
.get_maintainer.ignore:用于在使用
scripts/get_maintainer.pl
获取 Kernel 维护者的时候忽略此文件中列出的人员。 -
.gitattributes:
.gitattributes
是 Git 的配置文件之一,文件中的每一行定义一个/类文件/路径的若干属性,基本格式:文件 属性1 属性2 ...
。其中,文件名支持使用通配符(例如,*.c
表示所有 c 语言源码文件);属性有很多,常用的有 text、diff、eol 等。git 官方文档:https://git-scm.com/docs/gitattributes
-
.gitignore:
.gitignore
文件用来告诉 Git 忽略被记录在.gitignore
文件里的文件或文件夹的改动。被忽略的文件是不会被放入到远程仓库里的。注意,如果文件已经存在于远程仓库中,是无法通过.gitignore
文件来忽略的git 官方文档:https://git-scm.com/docs/gitignore
-
.mailmap:这个文件主要是记录了一些大神维护内核的名字和邮箱。git-shortlog 使用这个列表来修复 git 归档文件中一些糟糕的名称翻译,要么是因为作者的全名被弄乱了,要么是因为作者的书写方式不总是相同,导致同一个人的贡献看起来不是这样或显示得不好。也允许旧的电子邮件地址映射到新的电子邮件地址。
-
COPYING:Kernel 的版权说明,指出了 Kernel 使用的许可证。
-
CREDITS:自 1994 年 3 月 13 日起,CREDITS 文件就开始被包含在了 Kernel 根目录下。该文件中记录了为 Kernel 做过贡献的开发者的主要贡献领域、电子邮件和实际地址以及其他相关数据等基本信息。
-
Kbuild 和 Kconfig:K 指的是 Kernel,Kbuild 和 Kconfig 是 Kernel 的配置及编译构建系统。Kconfig 用来配置内核,它就是各种配置界面的源文件,内核的配置工具读取各个 Kconfig 文件,生成配置界面供开发人员配置内核,最后生成配置文件
.config
;Kbuild 则用于编译内核。- Kernel Build System
- Kbuild 和 Kconfig 就是对 Make 的进一步扩展
-
MAINTAINERS:这个文件列出了 Kernel 中每个子系统的维护者的基本信息。同时也给出了如何正确提交对内核的更改(PATCH)。
-
Makefile:它是 Kernel 配置及构建的入口。Kernel 使用 make 系统来管理构建过程。
-
README:这个文件就是一个简单的对于 Kernel 的自我介绍。由于 Kernel 包含了详细的文档,因此,该文件中并没有啥实质性的内容,就是作为一个入口,导航的其他介绍文档。
参考
- https://firstmonday.org/ojs/index.php/fm/article/view/1151/1071
- https://www.shuzhiduo.com/A/ke5j1RByJr/
- https://linux-kernel-labs.github.io/refs/heads/master/lectures/intro.html
- https://lwn.net/Articles/507794/
- https://blog.csdn.net/King_Rose/article/details/121512359
- https://en.wikipedia.org/wiki/Hybrid_kernel
- https://en.wikipedia.org/wiki/Linux_kernel
- https://abi-laboratory.pro/index.php?view=binary-compatibility
- https://en.wikipedia.org/wiki/Linux_kernel_interfaces
- https://www.geeksforgeeks.org/difference-between-microkernel-and-monolithic-kernel/