linux内核——入门

1. linus树

一直被认为linux内核源码的“根源”,因此一旦有新的版本,其他的开发树会将自己独特开发的成果移植到这个版本上,在此基础上再次开发。地位称为主线(mainline)。


2. 一旦发布新版本 Linus 树,就会立刻打开一个“合并窗口”(merge window),接受下一版本需要作出的改变。合并窗口将开启约两周时间。合并窗口关闭后,就会发布下一版本的候选版,即所谓的“rc 内核” 注 2 。从 rc 内核发布后到下一版本发布的期间为测试期,这一期间基本只接受关于 bugfix 的修改。rc 版内核每隔约一周时间会依次推出 rc ,rc2……当 Linus 判断其质量已经达到可以发布的水平时,就会作为新版本发布。按照最近的实际情况来看,基本上在 rc6 ~ rc9 左右就会发布新版本,也就是说 Linux 内核每
隔 2 ~ 3 个月就会发布新版本。新版本发布后,又会打开下一版本的合并窗口,然后对rc 版进行测试。Linux 内核就是按照这样的周期来开发的。 


3.linux-next 树
这是一个为发布将来的版本而积累新代码并进行测试的源码树,主要由 StephenRothwell 等人进行管理和运营。原则上要添加新功能或者进行安装配置时,首先要在linux-next 树中进行测试,在确认各自之间可以兼容之后再添加到 Linus 树内。


4. stable 树
这是一个主要只针对过去发布的内核版本进行 bug 修改,使其更加稳定的树,由 GregKroah-Hartman、Chris Wright 进行维护管理。这个树的版本号是在 Linus 树的版本号后面加一位数字,以 2.6.x.y 这样的 4 个数字来表示。针对某个 Linus 树版本的稳定(stable)版维护一般持续 6 个月左右,但也有持续更久的。


5.开发树
Linux 内核可以说是各种功能的集合体。例如内存管理、文件系统、网络、各种设备驱动程序、CPU 架构固有部分等。这些功能部分称为“子系统”,各子系统分别在不同
的源码树中进行开发。在开发、修改过程中也有一些不属于特定子系统的内容,这些内容首先会被发送到 Andrew Morton 管理的 mm 树(准确地说是 mmotm :mm on the
moment ,补丁包的缩写)。这样的源码树统称为“开发树”。在各开发树中开发出的源代码在经过 linux-next 中的测试后再植入 Linus 树。开发树的数量多如繁星。如果哪天你因为想要开发某个功能而在手边的源代码上进行了修改,这也可以说是一个“开发树”。Linus 树、开发树等作为所有树的根源,也称为“upstream”,即“上游”。但这是广义上
的叫法,有时也仅指最上游的 Linus 树。


6. 如何获取上游内核代码

在了解linux内核的版本,绝大部分的开发树都可以从 http://www.kernel.org/ 获取

下载 tar 文件
获取 Linus 树最简单的方法就是从 kernel.org 下载 tar 文件。2.6 内核所有发布版本的 tar
文件都能够从 http://www.kernel.org/pub/linux/kernel/v2.6/ 获取。


7. 使用Git

Git 是 Linux 内核所采用的 SCM(Source Code Management system),具备分散开发的多个功能。

$ git clone git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6(下载最新最全的版本代码)

保持最新的代码状态, 使用git pull(拉最新的代码到本地)


8. 安装code例子

# apt-get install linux-source

$ cp /usr/src/linux-source-2.6.35.tar.bz2 ~
$ cd
$ tar xjf linux-source-2.6.35.tar.bz2


9. 控制台:make menuconfig 会生成.config的配置文件

.config的文件内容如下:

#
# Automatically generated make config: don’t edit
# Linux/x86_64 2.6.38 Kernel Configuration
# Sun Mar 27 03:17:57 2011
#
CONFIG_64BIT=y
#CONFIG_X86_32 is not set
CONFIG_X86_64=y
CONFIG_X86=y
...
以 # 开头的行是注释行

设置项目(CONFIG_*)所取的值
值 说  明
=y 该项目所对应的功能将静态添加到内核中
=m 该项目所对应的功能将编译为模块。当内核在执行时,模
块会在需要时加载并添加到内核中。有一些功能无法作为
模块进行编译。在这种情况下对应的设置项目不取该值
# CONFIG_* is not set 该项目所对应的功能不编译。这些项目的行全部被注释掉


10. make 对象
对  象 说  明
clean 将源码树恢复到编译前的状态。obj 文件等被删除,.config或编译过程中自动生成的部分文件不会被删除
mrproper 将源码树完全恢复到发布时的状态。发布时源码树中不存在的文件全部被删除,包括 .config 文件
help 显示可以使用的 make 对象
tags 生成标签文件。有了标签文件,就能使用 Emacs 等编辑器的
tag jump 功能跳到函数定义处,可以高效进行源码浏览
cscope 生成用于 cscope 的索引文件。cscope 是基于控制台(文字界面)的源码浏览器
allyesconfig 生成将所有设置项目设置为有效并静态添加到内核中的 .config 文件
allnoconfig 生成将允许范围内的设置项目设置为无效的 .config 文件
allmodconfig 生成将所有能设置为模块的项目设置为有效并设置为模块的 .config 文件

/.o 仅进行生成指定的目标文件所必需的编译。当仅指定 时,由 .config 文件生成该目录内所有目标文件
/.ko 仅生成指定的模块展示了为控制 make 的输出而设置的 make 变量。这些变量需在对象前指定,如:
$ make V=1 clean


11. 编写特有的内核模块

以 mymod 模块为例说明,请将下面的代码以 mymod.c 为文件名保存。

#include 
#include 
#include 

static int sec = 5;
module_param(sec, int, S_IRUGO|S_IWUSR);
MODULE_PARM_DESC(sec, "Set the interval.");
static void mymod_timer(unsigned long data);
static DEFINE_TIMER(timer, mymod_timer, 0, 0);

static void mymod_timer(unsigned long data)
{
    printk(KERN_INFO "mymod: timer\n");
    mod_timer(&timer, jiffies + sec * HZ);
}

static int mymod_init(void)
{
printk(KERN_INFO "mymod: init\n");
if (sec <= 0) {
printk(KERN_INFO "Invalid interval sec=%d\n", sec);
return -EINVAL;
}
mod_timer(&timer, jiffies + sec * HZ);
return 0;
}

static void mymod_exit(void)
{
del_timer(&timer);
printk(KERN_INFO "mymod: exit\n");
}

module_init(mymod_init);
module_exit(mymod_exit);

MODULE_AUTHOR("Hiroshi Shimamoto");
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("My module");


在模块的源代码中包含(include)头文件 linux/module.h。
名为 module_int() 和 module_exit() 的宏,可以调用回调(callback)函数来进行初始化和终止模块的处理。在模块的源文件中进行如下描述,就可以在添加模块时调用初始化函数,在删除模块时调用终止函数。
module_init( 初始化函数名 );
module_exit( 终止函数名 );
在这个例子模块的情形下调用的分别是 mymod_init() 和 mymod_exit()。初始化函数为了表示初始化已正常完成,需要返回 0。按照 Linux 内核中的写法,发生错误(error)将返回一个值为负数的错误代码。在这个例子中,如果设定值出错,则处理为 -EINVAL(非法值)。
下面先用 3 个宏对模块进行定义,但在模块编写中并不是必需的。
MODULE_AUTHOR() 表示模块的作者
MODULE_LICENSE() 表示模块的许可证
MODULE_DESCRIPTION() 模块的说明
这个例子模块还用到了模块参数。模块参数可以使用 module_param() 宏来生成。
module_param( 参数名,参数类型,权限(permission));

接下来需要准备编写模块所需的 Makefile。由于是使用内核的创建框架来生成,因此Makefile 的内容非常简单。obj-m :=mymod.o最后执行下列 make 命令,通过当前目录(current directory)的源代码和 Makefile 生成模块 mymod.ko。
# make -C /lib/modules/'uname –r'/build M='pwd'
通过使用 modinfo 命令,可以看到所生成模块 mymod.ko 的信息。从这里可以看到使用 MODULE_* 宏所指定的内容。
# modinfo mymod.ko
filename: mymod.ko
description: My module
license: GPL
author: Hiroshi Shimamoto
srcversion: 61A3BB7CFC0C89B8344F5A5
depends:
vermagic: 2.6.32-71.29.1.el6.x86_64 SMP mod_unload modversions
parm: sec:Set the interval. (int)
添加内核模块
添加内核模块需要用到 insmod 命令或 modprobe 命令。
通过执行 insmod 命令把生成的 mymod.ko 模块添加进来。
# insmod mymod.ko
使用 dmesg 命令,可以看到例子模块 mymod.ko 的输出内容。
# dmesg | tail

mymod: init
作为模块初始化函数 mymod_init() 所调用的 printk() 的输出内容会在最后一行显示。
使用 lsmod 可以显示目前添加到内核中的模块列表。
# lsmod
Module Size Used by
mymod 1482 0
:
可以看到,mymod 行存在,模块已添加。
要将已添加的模块从内核空间删除时,可以使用 rmmod 命令。
# rmmod mymod
执行 rmmod 命令后,模块将从内核空间内删除,使用 lsmod 命令就不会再输出
mymod 行。


小贴士 :

1. Linus 树的内核由于完全没有任何华而不实的东西,因此称为“香草”(vanilla)内核或
“库存”(stock)内核。

2. rc 是 release candidate

3. 使用GnuPG来检测兼容时

$ gpg --keyserver wwwkeys.pgp.net --recv-keys 0x517DoFoE
$ gpg -verify < 签名文件 > < 下载的文件 >

4. .config文件不能手动编辑。

你可能感兴趣的:(linux内核——入门)