1 Linux内核简介
1 Unix的历史
1.Unix演化版实现了任务管理、换页机制、TCP/IP等新的特性。
2.Unix的特点:
- Unix很简洁,仅仅提供几百个系统调用并且有一个非常明确的设计目的;
- 在Unix中,所有的东西都被当做文件对待。
- Unix的内核和相关的系统工具软件是用C语言编写的,具有强大的移植能力
- Unix的进程创建非常迅速,并且有一个非常独特的fork()系统调用。
- Unix提供了一套非常简单但又很稳定的进程间通信元语,快速简洁的进程创建过程使Unix的程序把目标放在一次执行保质保量地完成一个任务上,简单稳定的进程间通信机制又使其能够方便组合,具备清晰的层次化结构。
3.Unix的现状:成为一种支持抢占式多任务、多线程、虚拟内存、换页、动态链接和TCP/IP的现代化操作系统。
2.Linux简介
1.Linux现在广泛移植到Alpha、ARM、PowerPC、SPARC、x86-64等其他体系结构之上。
2.Linux是类Unix系统,但不是Unix。Linux没有直接使用Unix的源代码,它的实现可能和其他各种Unix的实现大相径庭,但它没有抛弃Unix的设计目标并且保证了应用程序编程接口的一致。
3.Linux内核是*公开软件,是开源的。
4.Linux的基础是内核、C库、工具集和系统的基本工具。Linux这个词汇在本书中主要还是指内核。
3 .操作系统和内核简介
1.操作系统是指在整个系统中负责完成最基本功能和系统管理的部分。包括内核、设备驱动程序、启动引导程序、命令行shell、其他种类的用户界面、基本的文件管理工具和系统工具。
2.系统其他部分必须依靠内核这部分软件提供的服务,内核有时候被称作管理者或者操作系统核心,负责响应中断的中断服务程序,负责管理多个进程从而分享处理器时间的调度程序,负责管理进程地址空间的内存管理程序和网络和网络、进程间通信等系统服务程序.
3.内核一般处于系统态,拥有受保护的内存空间和访问硬件设备的所有权限,这种系统态和被保护起来的内存空间,统称为内核空间。
4 Linux内核和传统Unix内核的比较
1.Unix内核是一个不可分割的静态可执行库。必须以巨大、单独的可执行块的形式在一个单独的地址空间中运行。Unix内核通常需要硬件系统提供页机制(MUU)来管理内存。这样可以加强对内存空间的保护保证每个进程都而已运行于不同的虚地址空间上。
2.单内核与微内核设计的比较
操作系统内核可以分为两大阵营:单内核和微内核
1.单内核就是把它从整体上作为一个单独的大过程来实现、同时也运行在一个单独的地址空间上。内核通常以单个静态二进制文件的形式存放在磁盘中。
内核间通信、内核调用函数等与用户空间应用程序无异。
2.微内核的功能被划分为多个独立过程,每个过程称为服务器。微内核通信通过消息传递处理,即采用了进程间通信机制(IPM)。用于互换“服务”。服务器的独立自主有效地避免了一个服务器的失效祸及另一个,同样,模块化得系统允许一个服务器为了另一个服务器而换出。
5 Linux内核版本
1.Linux通过一个简单的命名机制来区分稳定的和处于开发中的内核。即用三个护着四个用“.”分割的数字来代表不同内核版本。第一个数字是朱版本号,第二个数字是从版本号,第三个数字是修订版本号,第四个可选的数字为稳定版本号。
2.从副版本号可以反映出该内核是一个稳定版本还是一个处于开发中的版本:如果数字为偶数,即是稳定版内核;若是奇数,则是开发版内核。
2 从内核出发
一、获取内核源码
1. Git
- git实际上是一种开源的分布式版本控制工具。
-
Linux作为一个开源的内核,其源代码也可以用git下载和管理
- 获取最新提交到版本树的一个副本
- $ git clone git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6.git
- 下载代码后,更新自己的分支到最新分支
- $ git pull
2.安装内核源代码
- 压缩形式为bzip2:
$ tar xvjf linux-x.y.z.tar.bz2
-
压缩形式为zip:
$ tar xvzf linux-x.y.z.tar.gz
关于参数:
-x 解开.tar格式的文件
-v 显示详细信息
-j 使用bzip2程序
-z 使用gzip程序
-f 使用归档文件
3. 使用补丁
从内部源码树开始,运行$ patch -p1 < ../patch-x,y,z
二、内核源码结构
详见LINUX内核分析第三周学习总结:构造一个简单的LINUX系统MENUOS中第一部分:“Linux内核源码简介”。
目 录 | 描 述 |
---|---|
arch | 特定体系结构的代码 |
block | 块设备I/O层 |
crypo | 加密API |
Documentation | 内核源码文档 |
drivers | 设备驱动程序 |
firmware | 使用某些驱动程序而需要的设备固件 |
fs | VFS和各种文件系统 |
include | 内核头文件 |
init | 内核引导和初始化 |
ipc | 进程间通信代码 |
kernel | 像调度程序这样的核心子系统 |
lib | 同样内核函数 |
mm | 内存管理子系统和VM |
net | 网络子系统 |
samples | 示例,示范代码 |
scripts | 编译内核所用的脚本 |
security | Linux 安全模块 |
sound | 语音子系统 |
usr | 早期用户空间代码(所谓的initramfs) |
tools | 在Linux开发中有用的工具 |
virt | 虚拟化基础结构 |
- COPYIN:内核许可证
- CREDITS:开发者列表
- MAINTAINTERS:维护者列表(维护内核子系统和驱动程序)
三、编译内核
1. 配置内核(关于make与config)
(1)相关
- Makefile:根据配置的情况,构造出需要编译的源文件列表,然后分别编译,并把目标代码链接到一起,最终形成 Linux 内核二进制文件。
- config.in:内核配置文件,给用户提供配置选择的功能。
- 配置工具:包括配置命令解释器(
make config
)和配置用户界面(例如:make menuconfig
:基于ncurse库的图形界面工具;make gconfig
:基于gtk+的图形工具...)。 - .config:用户用来存放内核配置后结果的文件。
- 可以配置的各种选项:用CONFIG_FEATURE形式表示,其前缀为CONFIG。
(2)命令
- make config:遍历所有配置项,并让用户选择
- make deconfig:按默认的配置
- make oldconfig:先将
/boot
目录下的配置文件写进.config
文件中,采用的是注释的形式写进新增加的功能。 - zcat /proc/config.gz > .config:配置选项
CONFIG_IKCONFIG_PROC
会把完整的压缩过的内核配置文件存放在/proc/config.gz
中,再次编译时可以方便地克隆当前的配置。 - make:默认的Makefile自动化编译。
2. 其它事项
-
减少垃圾信息
$ make > ../detritus
#将错误报告和警告信息重定向到文件中
$ make > /dev/null
#将无用的输出信息重定向到/dev/null中 - /dev/null:空设备,输入的信息直接丢弃 -
衍生多个编译作业:make程序能把编译过程拆分成多个并行的作业。其中每个作业独立并发地运行,有助于加快多处理器系统上的编译过程,也有利于改善处理器的利用率。默认情况下,make只衍生一个作业。
$ make -jn
#以多个作业编译内核 - j:指定同时执行多任务
- n:要衍生出的作业数
3. 安装新内核
make modules_install
#把所有已编译的模块安装到正确的主目录/lib/modules下
- System.map文件:编译时在内核代码树的根目录下创建的
符号对照表
。用来将内核符号与它们的起始地址对应起来。
四、内核开发特点
1. 无libc库/标准头文件
- 原因:(速度与大小)保证内核高效和简练。
- 内核源代码文件不能包含外部头文件。
- 基本头文件:内核源代码*目录下的
include
中 - 体系结构相关头文件:内核源代码树的
arch/<architecture>/include/asm
目录下
- 基本头文件:内核源代码*目录下的
- printk()函数:把格式化好的字符串拷贝到内核日志缓冲区上,syslog程序可以通过读取该缓冲区来获取内核信息。
2. 必须使用GNU C
什么是GNU?GNU是一种操作系统,GNU提供的C编译器就是我们之前使用的gcc。
(1)内联函数
static inline void wolf(unsigned long tail_size);
- static:关键字
- inline:用于限定关键字
- 内联函数:编译时在它被调用的地方展开。
- 优点:减少了函数调用的开销,性能较好。
- 缺点:频繁的使用内联函数也会使代码变长,从而在运行时占用更多的内存。
定义内联函数特点:时间要求高,本身长度较短的函数。
使用之前就要定义好内联函数,一般在头文件中定义。
为了类型安全和易读性,优先使用内联函数而不是复杂的宏。
(2)内联汇编
unsigned int low, high;
asm volatile("rdtsc" : "=a" (low), "=d" (high));
/* low 和 high 分别包含64位时间戳的低32位和高32位 */
- asm:嵌入汇编代码
- volatile:不优化
- 汇编语言用于偏近底层或对执行时间严格要求的地方。
(3)分支声明
/* 如果error在绝大多数情况下为0(假) */
if (unlikely(error)) {
/* ... */
}
/* 如果success在绝大多数情况下不为0(真) */
if (likely(success)) {
/* ... */
}
- 对于条件选择语句,在一个条件经常/很少出现时,编译器可通过gcc内建的一条指令对条件分支选择进行优化。
- 内核把这条指令封装成了宏。
3. 没有内存保护机制
- 内核自己非法访问内存的风险
- 内核中的内存都不分页:每用掉一个字节,物理内存都减少一个
4. 难以执行浮点运算
- 使用浮点数时,需要人工保存和恢复浮点寄存器及其他一些繁琐的操作。
- 不建议使用
5. 每个进程只有一个很小的定长堆栈
- 内核栈的大小是编译内核时决定的,对于不用的体系结构,内核栈的大小不一样,但都是固定的。(不像用户空间的栈可以动态增长)
6. 必须时刻注意同步和并发
- 原因:
- Linux是抢占多任务操作系统
- 内核支持对称多处理器系统(SMP)
- 中断异步到来
- 内核可以抢占
- 常用解决方法:自旋锁和信号量
7. 考虑可移植性的重要性
- 需要保持的特点:大部分C语言代码与体系结构无关。