一、内核简介
所谓内核即操作系统的内在核心,通常内核由中断服务程序、调度程序、内存管理程序和系统服务程序共同组成。其中,中断服务程序负责响应中断,调度程序负责管理多个进程从而分享处理器时间,内存管理程序负责管理进程地址空间,系统服务程序包括诸如网络、进程间通信等程序。
为了保护操作系统,内核独立于普通应用程序,它一般处于系统态,拥有受保护的内存空间和访问硬件设备的所有权限,其执行于内核空间。与之相对的是,应用程序在用户空间执行,它只能看到允许其使用的部分系统资源,不能直接访问硬件,也不能访问内核划给别人的内存范围。
当内核运行时,系统以内核态进入内核空间执行,而执行一个普通用户程序时,系统则以用户态进入以用户空间执行。
应用程序通过系统调用或者通过库函数(例如:C库函数)间接进行系统调用来与内核通信,让内核代其完成各种不同任务。
二、源码获取
登录Linux内核官网,可以随时获取当前版本的Linux源码。可以使用Git下载和管理Linux内核源码,如下命令可以获取最新提交到Linus版本树的一个副本:
#git clone git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6.git
当下载源码后,如下命令可以更新分支到Linus的最新分支:
#git pull
你也可以以补丁的形式发布对源码的修改,也可以以补丁的形式接收其他人所做的修改。要应用增量补丁,可以运行如下命令:
#patch -pl < ../patch-x.y.z
三、源码树
内核源码树由很多目录组成,而大多数目录又包含更多的子目录,具体描述如下:
目录
描述
arch
特定体系结构的源码
block
块设备I/O层
crypto
加密API
documentation
内核源码文档
drivers
设备驱动程序
firmware
使用某些驱动程序而需要的设备固件
fs
VFS和各种文件系统
include
内核头文件
init
内核引导和初始化
ipc
进程间通信代码
kernel
像调度程序这样的核心子系统
lib
通用内核函数
mm
内存管理子系统和VM
net
网络子系统
samples
示例,示范代码
scripts
编译内核所用的脚本
security
Linux安全模块
sound
语音子系统
usr
早期用户空间代码(所谓的initramfs)
tools
在Linux开发中有用的工具
virt
虚拟化基础结构
表1 内核源码树的根目录描述
四、编译源码
在编译内核源码前,你可以把自己需要的特定功能和驱动程序通过配置来编译进内核。配置选项类似于CONFIG_SMP的形式,前缀为CONFIG,SMP表示要启用或禁用的功能。
内核提供了各种工具来简化内核配置,常见的有三种:
(1)基于字符界面的命令行工具
#make config
(2)基于ncurse库的图形界面工具
#make menuconfig
(3)基于gtk+的图形界面工具
#make gconfig
你也可以用如下命令来生成默认配置:
#make defconfig
配置项会被存放在内核源码树根目录下的.config文件中,也可以直接打开这个文件修改配置选项,修改完配置文件之后编译内核之前,需要通过如下命令来验证和更新配置:
#make oldconfig
内核配置好后,就可以用如下命令来编译内核,激动人心的时刻即将到来:
#make
在编译源码时,默认会有大量信息从屏幕上一闪而过,若感不爽,可以如此这般:
#make > ../detritus
这样编译输出信息都会重定向到这个文件,如果你对此不感兴趣,可以将其扔进“黑洞”:
#make > /dev/null
内核的编译过程会有点小漫长,如果你是个急性子,可以把编译过程拆分成多个并行作业,每个作业独立并发地运行:
#make -jn
这里,n是并行作业数,一般每个处理器2个作业,即n=2*cpu,例如:32核处理器上,可以这样:
#make -j32 > /dev/null
当然也可以用distcc或者ccache来缩短内核编译时间。
编译好内核后,接下来就可以安装它了。内核的安装与体系结构和启动引导工具密切相关,对此,可以查阅启动引导工具说明,按照说明将内核映像copy到适当的位置,并按照启动要求安装它。
需要注意的是,为了保险起见,一定要保证有两个及以上可以启动的内核,以防止新编译的内核出现问题。例如:在使用grub的x86系统上,可以把arch/i386/boot/bzImage拷贝到/boot目录下,然后像vmlinuz-version一样命名它,并且编辑/etc/grub/grub.conf文件,为新内核建立一个新的启动项。
接下来以root身份,执行以下命令,就可以打完收工了:
#make modules_install
如果你对内核开发感兴趣,那么下面将要讲叙的内核开发特点对你至关重要。
五、内核开发特点
1、不能链接标准C库或者其它库
对于内核来说,C库太大且低效,大部分C库中的函数,内核中都有实现,基本的头文件都在内核源码树根目录的include目录下,而体系结构有关的头文件则位于arch//include/asm目录下,以x86体系结构为例,则体系结构相关的头文件位于arch/x86/include/asm目录下。
2、内核编程必须使用GNU C
Linux内核虽然是用C语言编写的,但是也有不按常理出牌的时候
,其并不完全遵循ANSI C标准,它用到了gcc提供的许多语言的扩展部分,具体如下:
(1)内联(inline)函数。
为了降低函数调用和返回带来的开销采用内联函数。
(2)内联汇编。
为了提高效率混合使用C语言和汇编语言。
(3)分支声明。
对于条件选择语句,gcc内建了一条指令用于优化,即当一个条件经常出现或该条件很少出现的时候,编译器可以根据这条指令对条件分支选择进行优化,内核吧这条指令封装成了宏,比如:likely()和unlikely()。
3、没有内存保护机制
当应用程序试图进行一次非法的内存访问时,内核会报错(SIGSEGV),并结束整个进程。但是如果内核做了类似出格的事,它会神不知鬼不觉的闪人
。内核中的内存都不分页,即没用掉一个字节,物理内存就减少一个字节,内核真是个诚实的好孩子,一点都不偷奸耍滑
。
4、难以执行浮点运算
在内核中使用浮点数时,除了要人工保存和恢复浮点寄存器,还有其它一些琐碎的事情要做。真够操劳的
。
5、每个进程只有一个很小的定长堆栈
内核堆栈的准确大小随体系结构而变化,在x86上,堆栈大小在编译时配置,可以使4KB也可以是8KB,但是从历史上说,内核堆栈的大小是两页,也就是32位机的内核堆栈是8KB,而64位机是16KB,这是固定不变的,每个处理器都有自己的堆栈。
6、同步与并发陷阱
内核支持异步中断,抢占和SMP,以至于其很容易产生竞争条件,这就要求有同步机制以保证不出现竞争条件。常用的解决竞争的办法是自旋锁和信号量,具体请听后文书分解。
7、可移植性的重要性
Linux是一个可移植的操作系统,因此,大部分代码应该与体系结构无关,要做到这点就必须把体系结构相关代码分离出来,这个在前面就可见端倪。
本集结束,敬请期待下集。。。