一、Linux内核的抽象结构
Linux内核由5个 主要的子系统组成:
1.进程调度(SCHED)控制着进程对CPU的访问。
当需要选择下一个进程运行时,由调度程序选择最值得运行的进程。
2.内存管理(MM)允许多个进程安全地共享主内存区域 。
Linux的内存管理支持虚拟内存,即在计算机中运行的程序,其代码、数据和堆栈的总量可以超过实际内存的大小,操作系统只将当前使用的程序块保留在内存中,其余的程序块则保留在磁盘上。必要时,操作系统负责在磁盘和内存之间交换程序块。
内存管理从逻辑上可以分为硬件无关的部分和硬件相关的部分。硬件无关的部分提供了进程的映射和虚拟内存的对换;硬件相关的部分为内存管理硬件提供了虚拟接口。
3. 虚拟文件系统(Virtul File System VFS)隐藏了各种不同硬件的具体细节,为所有设备提供了统一的接口,VFS还支持多达数十种不同的文件系统,这也是Linux较有特色的一部分。
虚拟文件系统可分为逻辑文件系统和设备驱动程序。逻辑文件系统指Linux所支持的文件系统,如ext2, fat等,设备驱动程序指为每一种硬件控制器所编写的设备驱动程序模块。
4.网络接口(NET)提供了对各种网络标准协议的存取和各种网络硬件的支持。
网络接口可分为网络协议和网络驱动程序两部分。网络协议部分负责实现每一种可能的网络传输协议,网络设备驱动程序负责与硬件设备进行通信,每一种可能的硬件设备都有相应的设备驱动程序。
5. 进程间通信(IPC) 支持进程间各种通信机制。
从图可以看出,处于中心位置的是进程调度,所有其它的子系统都依赖于它,因为每个子系统都需要挂起或恢复进程。
一般情况下,当一个进程等待硬件操作完成时,它被挂起;当操作真正完成时,进程被恢复执行。例如,当一个进程通过网络发送一条消息时,网络接口需要挂起发送进程,直到硬件成功地完成消息的发送,当消息被发送出去以后,网络接口给进程返回一个代码,表示操作的成功或失败。其它子系统(内存管理,虚拟文件系统及进程间通信)以相似的理由依赖于进程调度。
各个子系统之间的依赖关系如下:
· 进程调度与内存管理之间的关系:这两个子系统互相依赖。在多道程序环境下,程序要运行必须为之创建进程,而创建进程的第一件事,就是要将程序和数据装入内存。
· 进程间通信与内存管理的关系:进程间通信子系统要依赖内存管理支持共享内存通信机制,这种机制允许两个进程除了拥有自己的私有内存,还可存取共同的内存区域。
· 虚拟文件系统与网络接口之间的关系:虚拟文件系统利用网络接口支持网络文件系统(NFS),也利用内存管理支持RAMDISK 设备。
· 内存管理与虚拟文件系统之间的关系: 内存管理利用虚拟文件系统支持交换,交换进程(swapd)定期地由调度程序调度,这也是内存管理依赖于进程调度的唯一原因。当一个进程存取的内存映射被换出时,内存管理向文件系统发出请求,同时,挂起当前正在运行的进程。
除了图所显示的依赖关系以外,内核中的所有子系统还要依赖一些共同的资源,但在图中并没有显示出来。这些资源包括所有子系统都用到的过程,例如, 分配和释放内存空间的过程,打印警告或错误信息的过程,还有系统的调试例程等等。
二、源代码目录树结构
1、Linux内核的版本
在内核源码顶层目录下Makefile中查看版本号:
VERSION = 2 主版本号
PATCHLEVEL = 6 主版本号
SUBLEVEL = 31 次版本号
EXTRAVERSION = 扩展版本号
2、目录介绍
arch
与体系结构相关的代码。对应于每个支持的体系结构,有一个相应的子目录如x86、arm等,每个体系结构子目录下包含几个主要子目录:
.boot 启动内核所需的平台特有代码
.kernel 体系结构特有特征(如SMP)的实现
.mm 与体系结构相关的内存管理代码
.lib 与体系结构相关的通用函数的实现
block
部分块设备驱动程序。
crypto
常用加密和散列算法(如AES、SHA等),还有一些压缩和CRC校验算法。
Documentation
关于内核各部分的通用解释和注释。
drivers
所有设备驱动程序代码,它占整个内核代码量一半以上,每一个子目录对应一类驱动程序。
fs
文件系统代码,每个支持的文件系统有相应的子目录,如cramfs,yaffs,jffs2等
include
包括编译内核所需的大部分头文件,与平台无关的头文件放在include/linux子目录下,平台相关的头文件如include/asm-arm
init 内核初始化代码(注意不是系统引导代码)
kernel 内核管理核心代码
lib 库函数代码
Mm 内存管理代码
net 网络支持代码
sound 音频设备驱动代码
scripts 用于配置内核的脚本文件
security:主要是一个SELinux的模块
usr:实现了一个cpio
ipc:进程间通信的代码
一般在每个目录下都有一个.depend文件和一个Makefile文件。这两个文件都是编译时使用的辅助文件。仔细阅读这两个文件对弄清各个文件之间的联系和依托关系很有帮助。另外有的目录下还有Readme文件,它是对该目录下文件的一些说明,同样有利于对内核源码的理解。
三、makefile
- Makefile:顶层 Makefile,是整个内核配置、编译的总体控制文件。
- .config:内核配置文件,包含由用户选择的配置选项,用来存放内核配置后的结果(如 make config)。
- arch/*/Makefile:位于各种 CPU 体系目录下的 Makefile,如 arch/arm/Makefile,是针对特定平台的 Makefile。
- 各个子目录下的 Makefile:比如 drivers/Makefile,负责所在子目录下源代码的管理。
- Rules.make:规则文件,被所有的 Makefile 使用。
2、编译内核时Makefile的执行步骤包括两个过程:一是配置内核过程;二是编译生成内核目标文件的过程,稍微具体一点大致分为以下几步:
- 1) 配置内核 => 产生 .config文件;
- 2) 保存内核版本到include/linux/version.h文件中;
- 3) 符号链接include/asm to include/asm-$(ARCH);
- 4) 更新所有目标对象的其它前提文件,附加前提文件定义在arch/$(ARCH)/Makefile文件中;
- 5) 递归进入init- core- drivers- net- libs-中的所有子目录和编译所有的目标对象,上面变量值都引用到arch/$(ARCH)/Makefile文件中;
- 6) 链接所有的object文件生成vmlinux文件,vmlinux文件放在代码树根目录下。最开始链接的几个object文件列举在arch/$(ARCH)/Makefile文件的head-y变量中;
- 7) 最后体系Makefile文件定义编译后期处理规则和建立最终的引导映像bootimage。包括创建引导记录,准备initrd映像和相关处理。
3、编译哪些文件
(1)顶层makefile:决定内核目录下的子目录编进内核
(2)arch/$(ARCH)/Makefile:各级子目录(init-y、core-y等)下产生build—in.o/lib.a,head-y和这些文件一起编进内核。
(3)各级子目录下的makefile包含auto.conf。该文件包含的配置后产生的.config文件,进而决定哪些文件被编进内核,哪些编成模块。
2、怎么编译文件
3、怎么连接文件
顶层makefile中在init-y,core-y后面直接加上build-in.o/lib.a表示连接进入内核
四、Kconfig文件
1、配置工具通过读取arm/$(ARCH)/Kconfig文件生成配置界面,这个文件是总入口。内核源码的子目录下都有一个makefile和Kconfig文件
2、变量:
bool 两种取值:y、n
tristate 三种取值:y、n、m
string 字符串
hex 十六进制数据
int 十进制数据
3、语法:
menu: 用于生成菜单
config: 生成配置选项
depend on 依赖关系
default 默认值
select 自动选择
source 读入另一个Kconfig文件
help 帮助信息