首页 > 系统相关 >Linux内核——内核源码的探索+教你如何系统认识Linux内核源码树(推荐方式+推荐工具+推荐书目)

Linux内核——内核源码的探索+教你如何系统认识Linux内核源码树(推荐方式+推荐工具+推荐书目)

时间:2024-08-25 14:51:16浏览次数:11  
标签:代码 Linux 文件系统 源码 内核 linux

Linux

全称GNU/Linux,是一种免费使用和自由传播的类UNIX操作系统,该操作系统是由 Linus Torvalds于1991年10月5号首次发布, 它主要受到Minix和Unix思想的启发,是一个基于POSIX的多用户、多任务、支持多线程和多CPU的操作系统。严格地讲,Linux单指操作系统的内核,加上用户空间的应用程序之后,就成为Linux操作系统。和我们常用的windows系统相比,windows有漂亮的图形界面,方便操作,linux的shell操作劝退了很多入门者,不过,由于Linux源码公开、广泛的硬件支持、安全可靠性高以及优秀的开发工具链等优点,吸引了一大批开发者。Linux广泛应用在服务器主机超级计算机智能移动设备嵌入式设备

Linux内核

linux最早的版本号是0.11,由于比较古老,很多工具链已经不支持,导致编译也比较困难,不过还是有很多大神研究修改将其运行在新的硬件上,对于实用主义的初学者来说,无需花太多的精力去研究改造它。

内核源码树网站如下:

The Linux Kernel Archives

(进入网址后,可以选择对应的版本,在browse栏目中commit的download处下载源码树,也可以直接点击Latest Release下载最新版的源码树)

(1)找对应的v版本,进入深层目录中寻找对应版本

Index of /pub/linux/kernel/

 

(2)如果只具体到x.x版本,可以通过GitHub指定版本来直接下载(调整 /vx.x)

https://codeload.github.com/torvalds/linux/tar.gz/refs/tags/v5.4

为何要去探索内核?

一句话概括:有需求就有供给。

阅读内核源码目的:为了更好地编写驱动程序;对自己写的程序有更深入的理解;特别是当自己的岗位定位在底层开发。 (Linux最新的版本已经到达6.10.6,尽量选择长期稳定的版本来阅读)

在2020年初,对内核代码量进行统计情况

Linux内核Git源码树中的代码达到了2780万行。phoronix网站统计了Linux内核在进入2020年时的一些源码数据并作了总结。

从统计数据来看,Linux内核源码树共有:27852148行(包括文档、Kconfig文件、树中的用户空间实用程序等)、887925次commit21074位不同的作者2780万行代码分布在66492个文件中。

(Linux内核从最初的10000行代码到现在的2780万行代码就是全球精英共同贡献的结果。按照一天一万行的速度,也需要2700天,也需要7年多。这还是建立在所有代码逻辑看了的都懂,而且全部脉络一天接一天都不忘的基础上。实际上即使我们真的看完了,几年后内核又会有非常大的变化(一直在膨胀),可以说一辈子都无法真正地完全理解性看完Linux内核的代码。全部代码一行一行阅读几乎是一件不可能的事情,因此按需阅读。)

(对当前版本内核代码量感兴趣的,可以通过一些软件工具,如cloc或scc,可以大致进行统计)

cloc linux-5.10.0.tar.gz

相关Linux资讯网站(需要魔法上网)  https://www.phoronix.com/

统计数据来源 The Linux Kernel Enters 2020 At 27.8 Million Lines In Git But With Less Developers For 2019 - Phoronix

 统计信息  GitStats - linux

Linux内核Git源码树中的代码达到了2780万行,核心代码只有2%是由李纳斯•托瓦兹自己编写的,其他均是其他个人和组织贡献的,李纳斯•托瓦兹公开了Linux但保留了选择新代码和需要合并的新方法的最终裁定权。

当时除了Linus Torvalds,对内核贡献最多的是David S.Miller、 Mark Brown、Takashi Iwai、Arnd Bergmann、Al Viro和Mauro Carvalho Chehab。而参与贡献的公司,从域名统计来看,谷歌、Intel与Red Hat排在了最前列。

阅读源码分为纵向阅读横向阅读。纵向就是跟着内核的执行流程来读,横向就是按照内核的各大功能模块来读。

Linux分为内核态用户态, 学习Linux内核应先只关注内核态的模块,主要有进程管理内存管理设备驱动管理文件系统,以及系统调用硬件控制等。其中重点显而易见,即进程管理、内存管理、设备驱动管理和文件系统。

根据子系统划分如下:

总结了两种方式阅读源码,如下:

bochs+ linux0.11 + 书《linux内核完全注释、linux内核完全剖析、linux内核设计的艺术》
Source Insight (或者 vscode+clangd )+ 开发需求的linux内核版本 + 书《Linux内核源代码情景分析》

linux0.11代码量不是很大。《linux内核完全剖析》(建议阅读)《linux内核完全注释》是引导你横向阅读的书,《linux内核设计的艺术》是引导你纵向阅读的书。可以横向纵向结合着来,纵向跟着bochs(虚拟机软件,类似VMware,但VMware使用了虚拟化技术,部分指令直接交给硬件执行。而Bochs完全是靠软件模拟来实现的) 调试工具来是必不可少的,当遇到问题时进入到相应的功能模块横向拓展一下。

《Linux内核源代码情景分析》中的内核版本是2.4.X,现代内核版本还是推荐横向阅读,纵向几乎不可能(代码量庞大)。(在Linux下搭建了quem虚拟机,然后用GDB调试内核也可以)贵在坚持。

Linux源码树目录(通常情况)

以5.4版本为例:

arch 目录包括所有和体系架构相关的核心代码。它还有更深的子目录,每一个代表一种支持的体系架构

include 目录包括编译核心所需要的大部分 include 文件。它也有更深的子目录,每一个支持的体系结构一个。include/asm 是这个体系结构所需要的真实的 include 目录的软链接,例如 include/asm-i386 。为了改变体系结构,你需要编辑核心的 makefile ,重新运行 Linux 的核心配置程序

init 目录包含核心的初始化代码,这时研究核心如何工作的一个非常好的起点

mm 目录包括所有的内存管理代码。和体系结构相关的内存管理代码位于 arch/*/mm/

drivers 系统所有的设备驱动程序在这个目录。它们被划分成设备驱动程序类(大概占了一半大小)

ipc 目录包含核心的进程间通讯的代码

modules 这只是一个用来存放建立好的模块的目录

fs 所有的文件系统代码。被划分成子目录,每一个支持的文件系统一个

kernel 主要的核心代码。同样,和体系相关的核心代码放在 arch/*/kernel

net 核心的网络代码

lib 目录放置核心的库代码。和体系结构相关的库代码在 arch/*/lib/

scripts 目录包含脚本(例如 awk 和 tk 脚本),用于配置核心

系统了解参考入手顺序:

核心功能(kernel)、内存管理(mm)、文件系统(fs)、进程通讯(ipc)、网络(net)、系统启动和初始化(init/main和head.S)

内核子系统

内核在计算机科学中是一个用来管理软件发出的数据I/O(输入与输出)要求的计算机程序,将这些要求转译为数据处理的指令并交由中央处理器(CPU)及计算机中其他电子组件进行处理,是现代操作系统中最基本的部分。

它是为众多应用程序提供对计算机硬件的安全访问的一部分软件,这种访问是有限的,并由内核决定一个程序在什么时候对某部分硬件操作多长时间。linux内核代码涉及知识点包括汇编指令c语言硬件组成原理操作系统数据结构算法、各种外设总线驱动网络协议栈。直接对硬件操作是非常复杂的。所以内核通常提供一种硬件抽象的方法,来完成这些操作。通过进程间通信机制系统调用,应用进程可间接控制所需的硬件资源(特别是处理器及IO设备)。


最上面是用户(或应用程序)空间。这是用户应用程序执行的地方。用户空间之下是内核空间,Linux 内核正是位于这里。GNU C Library (glibc)也在这里。它提供了连接内核的系统调用接口,还提供了在用户空间应用程序和内核之间进行转换的机制。内核和用户空间的应用程序使用的是不同的保护地址空间。每个用户空间的进程都使用自己的虚拟地址空间,而内核则占用单独的地址空间。Linux 内核可以进一步划分成 3 层。最上面是系统调用接口,它实现了一些基本的功能,例如 read 和 write。系统调用接口之下是内核代码,可以更精确地定义为独立于体系结构的内核代码。这些代码是 Linux 所支持的所有处理器体系结构所通用的。在这些代码之下是依赖于体系结构的代码,构成了通常称为 BSP(Board Support Package)的部分。这些代码用作给定体系结构的处理器和特定于平台的代码。


内核主要系统包括:SCI:系统调用接口  PM:进程管理  VFS:虚拟文件系统   MM:内存管理
Network Stack:内核协议栈   Arch:体系架构   DD:设备驱动

系统调用接口

SCI 层提供了某些机制执行从用户空间到内核的函数调用。这个接口依赖于体系结构,甚至在相同的处理器家族内也是如此。SCI 实际上是一个非常有用的函数调用多路复用多路分解服务。在 ./linux/kernel 中您可以找到 SCI 的实现,并在 ./linux/arch 中找到依赖于体系结构的部分。

进程管理

进程管理的重点是进程的执行。在内核中,这些进程称为线程,代表了单独的处理器虚拟化(线程代码、数据、堆栈和 CPU 寄存器)。在用户空间,通常使用进程 这个术语,不过 Linux 实现并没有区分这两个概念(进程和线程)。内核通过 SCI 提供了一个应用程序编程接口(API)来创建一个新进程(fork、exec 或 Portable Operating System Interface [POSIX] 函数),停止进程(kill、exit),并在它们之间进行通信同步(signal 或者 POSIX 机制)。

内存管理

内核所管理的另外一个重要资源是内存。为了提高效率,如果由硬件管理虚拟内存,内存是按照所谓的内存页方式进行管理的(对于大部分体系结构来说都是 4KB)。Linux 包括了管理可用内存的方式,以及物理和虚拟映射所使用的硬件机制。

虚拟文件系统

虚拟文件系统(VFS)是 Linux 内核中非常有用的一个方面,因为它为文件系统提供了一个通用的接口抽象。VFS 在 SCI 和内核所支持的文件系统之间提供了一个交换层

在 VFS 上面,是对诸如 open、close、read 和 write 之类的函数的一个通用 API 抽象。在 VFS 下面是文件系统抽象,它定义了上层函数的实现方式。它们是给定文件系统(超过 50 个)的插件。文件系统的源代码可以在 ./linux/fs 中找到。文件系统层之下是缓冲区缓存,它为文件系统层提供了一个通用函数集(与具体文件系统无关)。这个缓存层通过将数据保留一段时间(或者随即预先读取数据以便在需要是就可用)优化了对物理设备的访问。缓冲区缓存之下是设备驱动程序,它实现了特定物理设备的接口。

网络堆栈

网络堆栈在设计上遵循模拟协议本身的分层体系结构。回想一下,Internet Protocol (IP) 是传输协议(通常称为传输控制协议或 TCP)下面的核心网络层协议。TCP 上面是 socket 层,它是通过 SCI 进行调用的。socket 层是网络子系统的标准 API,它为各种网络协议提供了一个用户接口。从原始帧访问到 IP 协议数据单元(PDU),再到 TCP 和 User Datagram Protocol (UDP),socket 层提供了一种标准化的方法来管理连接,并在各个终点之间移动数据。内核中网络源代码可以在 ./linux/net 中找到。

设备驱动程序

Linux 内核中有大量代码都在设备驱动程序中,它们能够运转特定的硬件设备。Linux 源码树提供了一个驱动程序子目录,这个目录又进一步划分为各种支持设备,例如 Bluetooth、I2C、serial 等。设备驱动程序的代码可以在 ./linux/drivers 中找到。

还是那句话:

linux内核源码庞大而不断膨胀,即使再聪明、再有精力,也不可能完全看完、看懂所有的linux内核源码。建议按照以下主线进行深入研究:

linux驱动架构 linux网络子系统 linux内核启动过程 linux内存管理机制 linux调度器

linux进程管理 linux虚拟机制(kvm) linux内核实时化技术

沿着某一个主线,深入进去,在研究清楚这个主线的同时,向其他的主线扩展、渗透和学习。

(之所以将驱动列为学习内核的入口,是因为内核为很多外设驱动实现了架构(子系统),比如I2C、SPI、UART、PCIE、字符设备、网络设备、块设备,可以从最基本的字符设备学起,学习如何编写一个简单的模块,学习如何为一些简单的设备比如LED、KEY、ADC等编写驱动,对于编写设备驱动可以参考我往期的文章进行了解哈,由点到线、由线到面、由面到体,层层深入、不断精进,是学习linux内核源码的一个有效的方法。)

学习Linux最重要的是培养自己写代码的能力和对Linux框架结构的了解

Linux内核中绝大部分代码都是由这个地球上顶尖的技术大牛所编写,这些代码的高内聚低耦合,其精准度,简洁度、质量都相当的高,每每看到一段高质量的代码,可能都会被那一行行枯燥的代码背后隐藏的设计思想所震撼,所折服!

阅读内核的代码简直就是在欣赏艺术品!
敲代码最多是提高代码的熟练度,看Linux内核定能提高代码的水平!愿各位都能够熟练掌握Linux,实现从程序员涅槃成为真正的软件大师!

(内核开发在很大程度上并不是重新造“轮子”的过程,而是深入理解并尽量复用现有的内核设计框架,然后参照相似的功能模块去添加或改写某项需要的功能。在对内核整体框架以及某些子系统融会贯通以后,我们才有可能站在巨人的肩膀上去改进框架本身,实现自主创新。如果过分强调不必要的“自主创新”,可能会让内核的可维护性变差,最终结果反而得不偿失。)

子系统入口

subsys_initcall

内核本身入口

start_kernel  
	-> rest_init();
		-> kernel_thread(kernel_init, NULL, CLONE_FS);
			-> kernel_init()
				-> kernel_init_freeable();
					-> do_basic_setup();
						-> do_initcalls(); 

总线、设备、驱动的概念+probe业务

在线阅读Linux内核源码网站:

https://elixir.bootlin.com/linux/latest/source

推荐书籍(参考)

《linux内核设计与实现》

《奔跑吧Linux内核 入门篇》和《奔跑吧Linux内核 》基于Linux4.x,以实际问题出发,在实际工作中很有用。

《Linux内核源代码情景分析》

《深入理解Linux内核》

《Linux设备驱动程序》

《现代体系结构上的Unix系统:内核程序员的SMP和Caching技术》

《Linux内核源代码完全注释》《Linux内核分析及编程》
TLDP(The Linux Documentation Project)中有大量文档《Linux Kernel Interls》《The Linux Kernel》《Linux Kernel Module Programming Guide》等

标签:代码,Linux,文件系统,源码,内核,linux
From: https://blog.csdn.net/weixin_56228133/article/details/141501427

相关文章