第一章 Linux内核简介
1. Unix的历史
-
Unⅸ虽然已经使用了40年,但计算机科学家仍然认为它是现存操作系统中最强大和最优秀的系统。
-
Unix强大的根本原因:
- 简洁
- 在Unix中所有的东西都被当做文件对待
- Unix的内核和相关的系统工具软件是用C语言编写的——正是这个特点使得Unix在各种硬件体系架构面前都具备令人惊异的移植能力
- Unix的进程创建非常迅速,并且有一个非常独特的fork()系统调用
- Unix提供了一套非常简单但又很稳定的进程间通讯元语,使得Unix的程序把目标放在一次执行保质保量的完成一个任务上
2 追寻Linus足迹:Linux简介
-
Linux是类Unix系统,但它不是Unix
-
Linux是一个非商业化的产品,和该系统的大部分一样,Linux内核也是自由(公开)软件
3 操作系统和内核简介
处理器在任何指定时间点上的活动范围可以概括为下列三者之一:
-
运行于内核空间,处于进程上下文,代表某个特定的进程执行。
-
运行于内核空间,处于中断上下文,与任何进程无关,处理某个特定的中断。
-
运行于用户空间,执行用户进程。
4 Linux内核和传统Unix内核的比较
Linux内核和传统Unix系统之间存在一些差异:1. Linux支持动态加载内核模块。2. Linux支持对称多处理(SMP)机制 3. Linux内核可以抢占。 4. Linux内核并不区分线程和其他的一般进程 5. Linux提供具有设备类的面向对象的设备模型、热插播事件以及sysfs
5 Linux内核版本
Kernel版本命名规则:
6 Linux内核开发者社区
这个社区重要论坛是Linux kernel mailing list(lkml)
第二章 从内核出发
2.1 获取内核源码
- 在Linux内核官方网站,可以随时获取当前版本的Linux源代码
2.1.1 使用Git
2.1.2 安装内核源代码
- 如果压缩形式是bzip2,则运行:
$ tar xvjf linux-x.y.z.tar.bz2
- 如果压缩形式是GNU的zip,则运行
$ tar xvzf linux-x.y.z.tar.gz
-
解压后的源代码位于linux-x.y.z.目录下。
-
何处安装源码:内核源码一般安装在/usr/src/linux目录下。
2.1.3 使用补丁
-
要应用增量补丁,从你的内部源码树开始,只是运行:
$ patch p1 < ../patch-x.y.z
-
一般说来,一个给定版本的内核补丁总是打在前一个版本上
2.2 内核源码树
2.3 编译内核
2.3.1 配置内核
-
可以配置的各种选项,以CONFIG_FEATURE形式表示,其前缀为CONFIG。
-
这些配置项要么是二选一,要么是三选一。二选一就是yes或no。比如说CONFIG_PREEMPT就是二选一,表示内核抢占功能是否开启。三选一可以是yes、no或module。Module意味着该配置项被选定了,但编译的时候这部分功能的实现代码是以模块(一种可以动态安装的独立代码段)的形式生成。在三选一的情况下,显然yes选项表示把代码编译进主内核映像中,而不是作为一个模块。驱动程序一般都用三选一的配置项。
2.3.2 减少编译的垃圾信息
-
我利用命令来对输出进行重定向
make >../detritus
-
一旦需要查看编译的输出信息,可以查看这个文件。不过,因为错误和警告都会在屏幕上显示,所以你需要看这个文件的可能性不大。事实上,我只不过敲入如下命令
$ make > /dev/null
这就把无用的输出信息重定向到永无返回值的黑洞/dev/null。
2.3.3 衍生多个编译作业
• 为了以多个作业编译内核,使用以下命令: $ make -jn • 这里,n是要衍生的作业数,在实际中,每个处理器上一般衍生一个或者两个作业。例如,在一个双处理器上,可以输入如下命令: $ make –j4
2.3.4 安装新内核
• 以root身份,只要运行: % make modules_install 就可以把所有已编译的模块安装到正确的主目录/lib下。
2.4 内核开发的特点
-
Linux内核编程与用户空间内应用程序开发的差异
1.Linux内核编程时不能访问C库
2.Linux内核编程时必须使用GNU C
3.Linux内核编程时缺乏像用户空间那样的内存保护机制。
4.Linux内核编程时浮点数很难使用。
5.内核只有一个很小的定长堆栈。
6.由于内核支持异步中断、抢占式和SMP,因此必须时刻注意同步和并发。
7.要考虑可移植性的重要性。
2.4.1 无libc库抑或无标准头文件
- 在所有没有实现的函数中,最著名的就数printf()函数了。内核代码虽然无法调用printf(),但它可以调用printk()函数。
2.4.2 GUNC
-
内核开发者使用的C语言涵盖了ISO C995标准和GNU C扩展特性。
- 内联(inline)函数
- 内联汇编
- 分支声明
2.4.3 没有内存保护机制
-
如果一个用户程序试图进行一次非法的内存访问,内核会发现这个错误,发送 SIGSEGV,并结束整个进程。
-
内核中发生的内存错误会导致oops,这是内核中出现的最常见的一类错误。
-
内核中的内存都不分页。
2.4.4 不要轻易在内核中使用浮点数
-
在执行浮点指令时到底会做些什么,因体系结构不同,内核的选择也不同,但是,内核通常捕获陷阱并做相应处理。
-
和用户空间进程不同,内核并不能完美地支持浮点操作,因为它本身不能陷入。
2.4.5 容积小而固定的栈
-
内核栈的准确大小随体系结构而变。在x86上,栈的大小在编译时配置,可以是4KB也可以是8KB。
-
从历史上说,内核栈的大小是两页,这就意味着,32位机的内核栈是8KB,而64位机是16KB,这是固定不变的。
2.4.6 同步和并发
-
Linux是抢占多任务操作系统。内核的进程调度程序即兴对进程进行调度和重新调度。内核必须对这些任务同步。
-
Linux内核支持多处理器系统。
-
中断是异步到来的,完全不顾及当前正在执行的代码。
-
Linux内核可以抢占。
2.4.7 可移植性的重要性
-
Linux是一个可移植的操作系统,
-
必须把体系结构相关的代码从内核代码树的特定目录中适当地分离出来。