天天看点

20130718:Linux内核编译

最近在学习《操作系统概念》一书,有些实验需要在系统内核中增加一些新的系统调用,由此便产生了修改内核源码并重新编译生成新内核的需求。我的思路是

首先搞定内核编译的流程,确保有个可用的实验环境,在此基础上再按照《操作系统概念》中的方法增加新的系统调用在内核中。

编译环境简单介绍下。

编译用的系统:Fedora core3,对应内核版本为2.6.9-1.677,gcc、make等都是fc3自带的,gcc是3.4.2,make是3.80,x86平台。

最开始下载了个2.6.36的内核源码,分别执行命令【make menuconfig】-【make bzImge】-【make modules】-【modules_install】-【make install】后,编译

生成的内核确实被部署在/boot/下,grub.conf中也增加了相应的启动项,但选中这一内核启动时便提示错误,目前没有搞明白到底是为什么,初步怀疑是新内核和

fc3系统的一些部分不兼容导致,因为目的是为了确保有个编译内核并可用的环境,便没有深究。

drivers/scsi/qla2xxx/qla_os.c: In function `qla2x00_queuecommand':
drivers/scsi/qla2xxx/qla_os.c:315: sorry, unimplemented: inlining failed in call to 'qla2x00_callback': function not considered for inlining
drivers/scsi/qla2xxx/qla_os.c:269: sorry, unimplemented: called from here
drivers/scsi/qla2xxx/qla_os.c:315: sorry, unimplemented: inlining failed in call to 'qla2x00_callback': function not considered for inlining
drivers/scsi/qla2xxx/qla_os.c:269: sorry, unimplemented: called from here
make[3]: *** [drivers/scsi/qla2xxx/qla_os.o] 错误 1
make[2]: *** [drivers/scsi/qla2xxx] 错误 2
make[1]: *** [drivers/scsi] 错误 2
make: *** [drivers] 错误 2
           

接下来下载了和fc3内核对应的2.6.9的源码,但在【make modules】时总是不成功,提示信息大概是与scsi相关的一些函数不是inline类型的,把【make bzImage】

生成的内核拷贝到/boot/下,并在grub.conf中增加相应启动项,结果启动菜单中选择新编译的内核启动时提示“unrecognized file format”,仔细检查发现把内核搞

错了,把源码目录linux-2.6.9下生成的vmlinux文件当做内核了,(虽然咨询过朋友说这个也是内核,但很明显文件格式都不一样),正确的应该用linux-2.6.9/arch/i386/

boot/目录下的bzImage,朋友们千万记住了哦。很遗憾的是即便用了正确的内核,发现启动过程中又提示无法加载/lib/modules等,总之依然报错,只是错误发生在启动

过程中了,同样,也没有时间去找原因。

最后,找了个Fedora Core14的系统,对应内核版本为2.6.35.6,gcc版本是4.5.1,make版本是3.82,依然是x86平台。下载与之对应的2.6.35.6的源码,解压至/usr/src下,

便生成了源码目录/usr/src/linux-2.6.35.6。编译内核的过程如下:

[[email protected]]#mv linux-2.6.35.6.tar.gz /usr/src

[[email protected]]#tar -xvzf linux-2.6.35.6.tar.gz

[[email protected]]#cd linux-2.6.35.6

[[email protected]]#make mrproper                           

[[email protected]]#make menuconfig                      # 配置内核

[[email protected]]#make dep                                     # 创建内核配置的依赖关系树

[roo[email protected]]#make clean                                  # 清楚旧版的*.o文件

[[email protected]]#make bzImage                            # 制作核心文件

[[email protected]]#make modules                           # 制作相关模块

[[email protected]]#make modules_name              # 安装模块到/lib/modules/`uname -r` 目录

[[email protected]]#make install                                # 安装内核文件到目录/boot

这时切换到/boot/下发现新的内核已经在了,grup.conf中也增加了相应的启动项,重启系统,选择编译后的新内核,成功启动。

下面对这个过程中自己所理解的一些东西进行描述,如有不当之处,欢迎各位指正。

make mrproper---这个命令用来确保源代码目录下没有不正确的目标.o文件以及文件的互相依赖,同时,还会删除源码目录下

的.config文件。.config文件中保存的是内核配置,新下载的源码包中是没有的,而且也不会存在不正确的.o文件等,因此这一步

对新下载的源码包可以省略。当你要对现有系统升级内核,而不修改内核的相关配置时,可以将当前系统的.config文件

(如果能找到的话O(∩_∩)O)拷贝到源码目录下使用。这一命令建议都执行一下,确保内核源码包中的内容是干净的。

有人说这一步后要确保/usr/include/目录下的asm、linux、scsi等连接是指向要升级的内核源码的,我没明白是为什么,也没有

做这一步。

make menuconfig---这是最常用来配合内核选项的命令,是基于文本选项的配置界面,字符终端下推荐使用。网上有人说要使用

这个命令必须安装ncurses-dev和tk4-dev库,因为我的机器上默认就能用,所以也没有验证这一点。当然还有基于文本的【make config】

和基于图形窗口的【make xconfig】(xwindows下推荐使用)。另外,【make oldconfig】据说是如果只想在原来内核配置的基础上

修改一些小地方可以使用,应该和上面说的“升级现有内核”但不修改配置等同,没有验证。

配置完成后保存退出,也会生成.config文件。

make dep---此命令用啦读取配置过程生成的.config配置文件,并创建对应于配置的依赖关系树,从而确定哪些需要编译,哪些不需要

编译。不过大家都说这条命令在2.6及以后的内核编译中都不再需要,如果执行就会出现“***Warning: make de is unnecessary now”

的提示。我编译2.6.9和2.6.35.6的内核时都执行过,确实是这个提示。

make bzImage----这个就是编译内核的命令了。此外还有【make zImage】,但zImage是用gzip压缩的,适合存储在软盘上。bzImage

是更大的超过软盘空间限制的压缩内核,我这里用的是bzImage。这个命令在目录/usr/src/linux-2.6.35.6/arch/i386/boot/下创建bzImage

文件,当然,这个文件是一个链接,指向../../x86/boot/bzImage,也就是真正的内核文件。

make modules---这个命令用来编译以生成相应的内核模块。

make modules_install---这个命令会在/lib/modules/目录下生成相应的2.6.35.6目录,该目录下即为编译过的内核模块。

/lib/modules/x.y.z是模块在系统中的标准目录。

make install---安装内核。这一命令会将生成的/usr/src/System.map、/usr/src/linux-2..35.6/arch/i386/boot/bzImage拷贝

到/boot/下,并修改grub.conf启动菜单配置,实际上就是将编译出的内核安装到当前系统中。

至此,编译内核过程完成,而且已经安装到当前系统,重启系统发现启动项中多了新内核的启动项,选择之,启动即可。

【make modules】 以及【make modules_install】命令有人说不必要,目前为止我还没搞清楚它和编译内核的关系,但

感觉其生成的内核模块(即*.ko)文件在内核运行过程中若需要加载时是需要的,所以建议还是一起做了。

补充:

额外模块的安装。----------------这是从网上摘抄的,没有试验过。

比如我现在给机器加了个Intel 3945的无线网卡,那么要使其能正常使用,就要安装其对应的驱动模块。

tar -xvzf ipw3945-1.2.2.gz

cd ipw3945-1.2.2

将编译出来的模块文件ipw3945.ko一道核心目录,并更新模块的依赖属性:

cp ipw3945.ko /lib/modules/`uname -r`/kernel/drivers/net

cd /lib/modules/`uname -r`

depmod -a

开机自动加载模块:

cd /etc/sysconfig/modules

echo "modprobe ipw3945" >> my.modules

chmod 755 my.modules

重启后查看模块是否加载:

lsmod |grep ipw3945

ps:每次更新kernel后需要重新编译一次额外添加的模块。

核心模块管理:

lsmod :列出所有模块

modinfo:查看模块信息

modprobe:-c      查看配置文件

                       -l       列出所有模块

                       -r      移除模块

insmod:插入模块

rmmod:删除模块