制作initrd(1):向initrd内部更新驱动模块

时间:2022-11-08 07:57:10


    从centos到ubuntu,grub从grub1进化到grub2,其配置文件的内容也跟着发生了巨大的变化。但是配置文件中有几项参数一直变化不大:linux root和initrd,一直指向内核镜像 根设备和initrd镜像的路径。就算换到uboot上,依然能见到这三项参数,其重要性可见一斑。3个参数以内核镜像最重要,而initrd却是时有时无的参数。

    虽然initrd的存在感不强,但却是本文核心角色。这起源于最近制作LFS,大部分时间花在制作initrd上;另外公司外包一个小系统出去,其核心部分也是定制initrd。出于这些原因,记录于此以备查阅。

    按grub.cfg的设置,initrd常化名为initrd.img-`uname -r`定居于/boot目录。编译内核代码执行make modules_install后会生成initrd.img,这是一个经cpio打包然后gzip压缩的文件,因此,完全可以把initrd.img解剖了研究。

#file initrd.img-3.13.0
initrd.img-3.13.0:gzip compressed data
#mv initrd.img-3.13.0 initrd.img-3.13.0.gz
#gunzip initrd.img-3.13.0.gz
#file initrd.img-3.13.0
initrd.img-3.13.0:ASCII cpio archive
#cpio -i --make-directories < initrd.img-3.13.0 #解包
#ls
bin init run conf sbin etc lib scripts




从initrd.img解压的结果来看,initrd.img文件中也包含了一个跟文件系统的雏形。据悉,如果配置内核源码,使之支持initramfs(make menuconfig时在General setup中选中Inital RAM filesystem and RAM disk选项),当系统启动时,内核会创建一个ramdisk,把initrd.img的内容解压到其中,这样内核中就有一个临时个根文件系统,加载类似scsi驱动。关于这个根文件系统的作用,我将另起一文记录。

    有过嵌入式经验的读者都知道,这个根文件系统中有个至关重要的用户态进程--udev,负责加载模块。上文已经说道这个临时根文件系统会加载scsi模块,可是scsi模块在哪?可以从udev的行为来推出模块路径。udev启动时按/etc/modprobe.d/目录下的规则文件(*.rules)的设置,去/lib/modules/`uname -r`目录下加载模块。由此可知scsi模块路径十有八九在此了:

#以下命令执行在上面被肢解的initrd.img文件夹下
#cd lib/modules/3.13.0/kernel/drivers
#ls
ata ... block ... scsi uio

这些模块是执行make modules_install时被安装到/lib/modules/`uname -r`/目录下,而在make modules_install的结尾部分,Makefile会调用mkinitramfs将一些模块添加到initrd中。

    看到这,我觉得大家对initrd有个感性认识了。那好,我有个问题,如何在系统启动时加载一个模块?目前,我知道3种方式:

1.在类似/etc/initrc等配置文件的末尾加入insmod xx.ko,这个是最容易想到的

2.另一种方式,就是在/etc/modules文件中添加开机时需要装入的模块的模块名,来看下modules自己的注释:

# /etc/modules: kernel modules to load at boot time.
#
# This file contains the names of kernel modules that should be loaded
# at boot time, one per line. Lines beginning with "#" are ignored.

中文我就不翻译了。这里有一点需要注意,将被insmod的模块的位置不是随便指定的,必须在/lib/modules/(`uname -r`)/kernel/driver的子目录下能找到该模块。


以我的环境为例:我用的os是公版的ubuntu 12.04,另外, 桌面上待编译的内核为linux-3.13

root@ubuntu:~# uname -r
3.13.0-32-generic
root@ubuntu:~# cat /etc/issue
Ubuntu 12.04.5 LTS \n \l
root@ubuntu:~# cd ~/Desktop/linux-3.13/
root@ubuntu:~/Desktop/linux-3.13# pwd
/root/Desktop/linux-3.13

两个内核的区别是,我往待编译的内核上添加了2个测试模块:

制作initrd(1):向initrd内部更新驱动模块

经过make all&&make modules_install&&make install后,在/boot/grub/grub.cfg中有两个启动项:

#公版启动项
menuentry 'Ubuntu, with Linux 3.13.0-32-generic' --class ubuntu --class gnu-linux --class gnu --class os {
recordfail
gfxmode $linux_gfx_mode
insmod gzio
insmod part_msdos
insmod ext2
set root='(hd0,msdos1)'
search --no-floppy --fs-uuid --set=root 9a661d2c-4456-4d23-93f2-60544bc54fe3
linux /boot/vmlinuz-3.13.0-32-generic root=UUID=9a661d2c-4456-4d23-93f2-60544bc54fe3 ro quiet splash $vt_handoff
initrd /boot/initrd.img-3.13.0-32-generic
}
#添加了Simple模块的启动项
menuentry 'Ubuntu, with Linux 3.13.0' --class ubuntu --class gnu-linux --class gnu --class os {
<span style="white-space:pre"> </span>recordfail
<span style="white-space:pre"> </span>gfxmode $linux_gfx_mode
<span style="white-space:pre"> </span>insmod gzio
<span style="white-space:pre"> </span>insmod part_msdos
<span style="white-space:pre"> </span>insmod ext2
<span style="white-space:pre"> </span>set root='(hd0,msdos1)'
<span style="white-space:pre"> </span>search --no-floppy --fs-uuid --set=root 9a661d2c-4456-4d23-93f2-60544bc54fe3
<span style="white-space:pre"> </span>linux<span style="white-space:pre"> </span>/boot/vmlinuz-3.13.0 root=UUID=9a661d2c-4456-4d23-93f2-60544bc54fe3 ro quiet splash $vt_handoff
<span style="white-space:pre"> </span>initrd<span style="white-space:pre"> </span>/boot/initrd.img-3.13.0
}

为了在系统引导时加载Simple模块,我的/etc/modules配置为:

# /etc/modules: kernel modules to load at boot time.
#
# This file contains the names of kernel modules that should be loaded
# at boot time, one per line. Lines beginning with "#" are ignored.

lp
simple_ops_export
simple

重启ubuntu后,选择进入3.13.0,进入系统后lsmod|grep -i simple即可看到新添加的模块


制作initrd(1):向initrd内部更新驱动模块


root@ubuntu:~# lsmod|grep -i simple
simple 799 0
simple_ops_export 1184 1 simple
root@ubuntu:~# uname -r
3.13.0

但是如果进入Ubuntu, with Linux 3.13.0-32-generic,则系统引导后lsmod的结果中不会有Simple模块,因为/lib/modules/(`uname -r`)/kernel/driver下根本不存在这个模块

root@ubuntu:~# uname -r
3.13.0-32-generic
root@ubuntu:~# lsmod|grep -i simple
root@ubuntu:~#

3.最后一种方法就是向initrd内部更新Simple驱动模块,这也是标题的题意。

这种方法需要借用mkinitramfs套件,mkinitramfs会把/lib/modules/`uname -r`目录下一些启动必须的模块添加到initramfs中。如果用户需要手动添加一些模块,可以通过/etc/initramfs-tools/modules文件中加入模块名来实现。

来看下修改该文件前后initrd.img的变化:

3-1):默认情况下的/etc/initramfs-tools/modules

# List of modules that you want to include in your initramfs.
# They will be loaded at boot time in the order below.
#
# Syntax: module_name [args ...]
#
# You must run update-initramfs(8) to effect this change.
#
# Examples:
#
# raid1
# sd_mod
# Beginning of the block added by the VMware software - DO NOT EDIT
vmxnet3
vmw_pvscsi
<span style="font-family: Arial, Helvetica, sans-serif;"># End of the block added by the VMware software</span>
root@ubuntu:~# update-initramfs -u -k 3.13.0
cp /boot/initrd.img-3.13.0 ~/Desktop/<span style="font-family: Arial, Helvetica, sans-serif;">initrd.img-3.13.0.gz</span>
<span style="font-family: Arial, Helvetica, sans-serif;">#gunzip </span><span style="font-family: Arial, Helvetica, sans-serif;">~/Desktop/</span><span style="font-family: Arial, Helvetica, sans-serif;">initrd.img-3.13.0.gz</span><pre name="code" class="cpp">#cpio -i --make-directories < initrd.img-3.13.0
<pre name="code" class="cpp">root@ubuntu:~/Desktop# cd lib/modules/3.13.0/
root@ubuntu:~/Desktop/lib/modules/3.13.0#ls

modules.alias      modules.dep.bin  modules.softdep


modules.alias.bin  modules.devname  modules.symbols


modules.dep        modules.order    modules.symbols.bin




3-2):修改/etc/initramfs-tools/modules后

# List of modules that you want to include in your initramfs.
# They will be loaded at boot time in the order below.
#
# Syntax: module_name [args ...]
#
# You must run update-initramfs(8) to effect this change.
#
# Examples:
#
# raid1
# sd_mod
# Beginning of the block added by the VMware software - DO NOT EDIT
vmxnet3 #附注,这里可以看出vmware如何添加vmtools模块
vmw_pvscsi
simple_ops_export
sample
# End of the block added by the VMware software
<pre name="code" class="cpp">root@ubuntu:~# update-initramfs -u -k 3.13.0
cp /boot/initrd.img-3.13.0 ~/Desktop/<span style="font-family: Arial, Helvetica, sans-serif;">initrd.img-3.13.0.gz</span>
<span style="font-family: Arial, Helvetica, sans-serif;">#gunzip </span><span style="font-family: Arial, Helvetica, sans-serif;">~/Desktop/</span><span style="font-family: Arial, Helvetica, sans-serif;">initrd.img-3.13.0.gz</span><pre name="code" class="cpp">#cpio -i --make-directories < initrd.img-3.13.0



<pre name="code" class="cpp">root@ubuntu:~/Desktop# cd lib/modules/3.13.0/
root@ubuntu:~/Desktop/lib/modules/3.13.0#ls #多了一个kernel文件夹


kernel             modules.dep      modules.order    modules.symbols.binmodules.alias      modules.dep.bin  modules.softdepmodules.alias.bin  modules.devname  modules.symbols


root@ubuntu:~/Desktop/lib/modules/3.13.0# cd kernel/drivers/char
root@ubuntu:~/Desktop/lib/modules/3.13.0/kernel/drivers/char# ls
simple_ops_export.ko

再次启动进入3.13.0内核查看模块加载结果(去掉/etc/modules文件中的配置,以免影响测试):

制作initrd(1):向initrd内部更新驱动模块


root@ubuntu:~# uname -r
3.13.0
root@ubuntu:~# lsmod|grep -i simple
simple_ops_export 1184 0
root@ubuntu:~#

这个结果充分说明了,方法3也是一种不错的方法~~