最近在阅读ELDD,此书偏向于实战,但是有些年代了,才看了不到几页,便遇到了一些坑。
现在,大家使用的linux内核的操作系统,多为各大发行版,在ELDD一书中,第一章便要让大家去直接下载kernel.org提供的源码,略作修改后,用该内核启动。然后不知是不是中文版翻译的问题,这里作者的本意应该是使用和现有的内核相同的版本,然后生成bzImage,这样不就用去管initrd,直接把grub中使用的内核镜像(vmlinuz)路径改为自己的即可正常启动。
这里要注意的一点是,发行版的内核即使版本号和官网相同或接近,差异也可能较大,所以获取内核源码尽量去下载发行版的源码,下面以centOS为例。(因为ELDD一书中使用的是2.6.23/24的代码,但是发行版没怎么看到使用这个版本的内核镜像,干脆就用了centOS6.9,2.6.32的内核)
centOS的内核源码可在 http://vault.centos.org/ 处获取,使用uname -a
查看自己的内核版本,找到对应的版本后,下载之。
得到.rpm文件后,使用rpm -i XXX.rpm
命令,可以得到一个 rpmbuild/SPECS/kernel.spec 文件
使用rpmbuild -bp --target=$(uname -m) kernel.spec
命令,就可在 rpm/BUILD 目录下找到kernel对应的文件姐,其内便是源码
有了源码,并肆无忌惮(划掉)的修改后,就可以开始着手内核的编译和安装了。
首先,让我们列出安装新内核需要的文件:
bzImage:内核的压缩镜像
System.map:内核符号表
initramfs.XXX.img:initial ram filesystem,关于initramfs的说明请见我另外一篇文章。
/lib/modules/X.Y.Z:内核模块文件夹
grub.conf:grub的配置文件
在生成所需文件之前,我们首先需要进行一些配置,这一步骤可以使用 make menuconfig
来进行图形界面配置,可以使用 cp arch/x86/configs/x86_64_default.config .config
来使用一些默认的配置,也可以使用 make oldconfig
来使用已有的内核的配置。
完成配置后,就可以开始生成各种所需文件了,具体见下:
bzImage:make bzImage
& cp arch/x86_64/boot/bzImage /boot/vmlinuz-X.Y.Z
(生成的bzImage的位置视内核版本会有微妙的不同)
System.map:make bzImage
& cp arch/x86_64/boot/bzImage /boot/System.map-X.Y.Z
initramfs.XXX.img:mkinitramfs -o /boot/initramfs-X.Y.Z.img X.Y.Z
(此处的版本号主要用于找到 /lib/modules/X.Y.Z)
/lib/modules/X.Y.Z:make modules
& make modules_install
gurb.conf的修改见下
tips:上述安装为手动安装,最简单的安装自然是make & make modules_install & make install
,另外make bzImage & make modules & make modules_install & make install
也是ok的。需要注意的是make modules_install
一定要在make install
之前,原因见下。
其中,make bzImage
用于生成bzImage和System.map,make modules
用于生成模块文件,make modules_install
将在/lib/modules
下创建对应版本的文件夹并把所需文件拷贝和链接到该文件夹下后生成模块依赖关系文件,make install
通过调用/sbin/installkernel
生成initramfs.img,并把bzImage、System.map和initramfs.img放到/boot
下后重命名,其中生成initramfs.img时需要用到/lib/modules
下的对应版本的文件夹。
ps:/sbin/installkernel
是shell脚本
这里采用的不是grub2,下文的方法并不适用于grub2
/boot/grub/grub.conf
是grub开机引导的配置文件,所有的引导条目都是在这里配置的,一个引导看起来应该是这样的:
title CentOS (2.6.32)
root (hd0,0)
kernel /vmlinuz-2.6.32 ro root=/dev/mapper/VolGroup-lv_root rd_NO_LUKS LANG=en_US.UTF-8 rd_NO_MD rd_LVM_LV=VolGroup/lv_swap SYSFONT=latarcyrheb-sun16 crashkernel=auto rd_LVM_LV=VolGroup/lv_root KEYBOARDTYPE=pc KEYTABLE=us rd_NO_DM rhgb quiet
initrd /initramfs-2.6.32.img
下面逐行说明:
title CentOS (2.6.32)
正如字面上的意思,表示的是引导的名字,这里填写的时候应该尽量清楚,比如带上版本号
root (hd0,0)
首先,需要注意的是,这里的root并不是我们平常理解的根目录\
,而是对grub来说的根目录,也就是boot
所在的分区,或者直接就是boot
分区,如hd0表示的是第一块硬盘,而(hd0,0)就是指第一块硬盘的第一个分区(如果不是很理解,请看下面 其他)
kernel /vmlinuz-2.6.32 ro root=/dev/mapper/VolGroup-lv_root rd_NO_LUKS LANG=en_US.UTF-8 rd_NO_MD rd_LVM_LV=VolGroup/lv_swap SYSFONT=latarcyrheb-sun16 crashkernel=auto rd_LVM_LV=VolGroup/lv_root KEYBOARDTYPE=pc KEYTABLE=us rd_NO_DM rhgb quiet
这句话比较长,但是核心只有这一句kernel /vmlinuz-2.6.32 ro root=/dev/mapper/VolGroup-lv_root
。
首先kernel /vmlinuz-2.6.32
指明了内核镜像所在的位置(相对于/boot
)。而后的ro root=/dev/mapper/VolGroup-lv_root
表示以只读方式挂载根分区(ro并非必要的,只是以防万一),注意此处的root为根分区,也就是说这里的root=
后面表面的是\
分区表示的设备。
设备的表示方式可以采用uuid,如root=UUID=488de085-08b9-4554-917e-4bc78059a998
,可以采用设备名,如root=/dev/sda1
,还可以采用逻辑设备名,如root=/dev/mapper/VolGroup-lv
splashimage=(hd0,0)/grub/splash.xpm.gz
这里我们需要告诉grubsplash.xpm.gz
这个文件所在的位置,但是对grub而言,它看到的磁盘空间可不是向我们不一样,我们看到的是\
目录下有若干文件/文件夹,而它看到的是若干个磁盘和分区,举两个例子:
\
分区单独分区,boot
没有单独分区,就在\
下面,假设\
分区在第一块硬盘的第一个分区上,则该语句为:splashimage=(hd0,0)/boot/grub/splash.xpm.gz
意思很简单,我们能够在第一块硬盘的第一个分区的boot/grub
目录下找到splash.xpm.gz
\
单独分区,boot
也单独分区,假设\
在第一块硬盘的第一个分区,boot
在第一块硬盘的第二个分区,则该语句为:splashimage=(hd0,1)/grub/splash.xpm.gz
意思也是显而易见的,因为boot
单独分区了,自然不在\
这一分区下面,同时grub
目录也就直接在boot
分区下(觉得抽象的话,就想boot
不再是\
下的一个文件夹,而是一个单独的分区)。
这里内核安装的本意是完全手动安装,以理解安装一个内核到底实际需要哪些东西,但是modules的手动安装目前还不是很清楚,故而只能退而求其次,使用make modules_install
而make modules_install
目测应该不只是安装这么简单,/lib/modules/X.Y.Z 下的部分文件在源码目录和其他任何非 /lib/modules/* 目录下都找不到,所以make modules_install
应该包含了编译安装以及清除文件的功能(可能使用的是mv)。(实际过程见下)
查了一下没查出个什么名堂,还是翻开了Makefile,发现modules_install这一块干的事情意外的简单。
第一步,把源码目录下的source和build 链接/拷贝到 /lib/modules/X.Y.Z 下
第二步,使用make -f
make了源码目录下 scriprts 中的Makefile.modinst 和 Makefile.fwinst
第三步,调用了depmod,生成了模块依赖关系文件dep,系统启动时加载模块就是从dep里面读取信息加载模块