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

从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解剖了研究。

  1. #file initrd.img-3.13.0  
  2. initrd.img-3.13.0:gzip compressed data  
  1. #mv initrd.img-3.13.0 initrd.img-3.13.0.gz  
  1. #gunzip initrd.img-3.13.0.gz  
  1. #file initrd.img-3.13.0  
  1. initrd.img-3.13.0:ASCII cpio archive  
  1. #cpio -i --make-directories < initrd.img-3.13.0 #解包  
  1. #ls  
  1. 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模块路径十有八九在此了:

  1. #以下命令执行在上面被肢解的initrd.img文件夹下  
  2. #cd lib/modules/3.13.0/kernel/drivers  
  3. #ls  
  4. 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自己的注释:

  1. # /etc/modules: kernel modules to load at boot time.  
  2. #  
  3. # This file contains the names of kernel modules that should be loaded  
  4. # 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
  1. root@ubuntu:~# uname -r  
  2. 3.13.0-32-generic  
  3. root@ubuntu:~# cat /etc/issue  
  4. Ubuntu 12.04.5 LTS \n \l  
  1. root@ubuntu:~# cd ~/Desktop/linux-3.13/  
  2. root@ubuntu:~/Desktop/linux-3.13# pwd  
  3. /root/Desktop/linux-3.13  

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

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

  1. #公版启动项  
  1. menuentry 'Ubuntu, with Linux 3.13.0-32-generic' --class ubuntu --class gnu-linux --class gnu --class os {  
  2.     recordfail  
  3.     gfxmode $linux_gfx_mode  
  4.     insmod gzio  
  5.     insmod part_msdos  
  6.     insmod ext2  
  7.     set root='(hd0,msdos1)'  
  8.     search --no-floppy --fs-uuid --set=root 9a661d2c-4456-4d23-93f2-60544bc54fe3  
  9.     linux   /boot/vmlinuz-3.13.0-32-generic root=UUID=9a661d2c-4456-4d23-93f2-60544bc54fe3 ro   quiet splash $vt_handoff  
  10.     initrd  /boot/initrd.img-3.13.0-32-generic  
  11. }  
  1. #添加了Simple模块的启动项  
  2. menuentry 'Ubuntu, with Linux 3.13.0' --class ubuntu --class gnu-linux --class gnu --class os {  
  3. <span style="white-space:pre">    </span>recordfail  
  4. <span style="white-space:pre">    </span>gfxmode $linux_gfx_mode  
  5. <span style="white-space:pre">    </span>insmod gzio  
  6. <span style="white-space:pre">    </span>insmod part_msdos  
  7. <span style="white-space:pre">    </span>insmod ext2  
  8. <span style="white-space:pre">    </span>set root='(hd0,msdos1)'  
  9. <span style="white-space:pre">    </span>search --no-floppy --fs-uuid --set=root 9a661d2c-4456-4d23-93f2-60544bc54fe3  
  10. <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  
  11. <span style="white-space:pre">    </span>initrd<span style="white-space:pre"> </span>/boot/initrd.img-3.13.0  
  12. }  
为了在系统引导时加载Simple模块,我的/etc/modules配置为:
  1. # /etc/modules: kernel modules to load at boot time.  
  2. #  
  3. # This file contains the names of kernel modules that should be loaded  
  4. # at boot time, one per line. Lines beginning with "#" are ignored.  
  5.   
  6. lp  
  7. simple_ops_export  
  8. simple  
重启ubuntu后,选择进入3.13.0,进入系统后lsmod|grep -i simple即可看到新添加的模块

  1. root@ubuntu:~# lsmod|grep -i simple  
  2. simple                   799  0   
  3. simple_ops_export       1184  1 simple  
  4. root@ubuntu:~# uname -r  
  5. 3.13.0  
但是如果进入Ubuntu, with Linux 3.13.0-32-generic,则系统引导后lsmod的结果中不会有Simple模块,因为/lib/modules/(`uname -r`)/kernel/driver下根本不存在这个模块
  1. root@ubuntu:~# uname -r  
  2. 3.13.0-32-generic  
  3. root@ubuntu:~# lsmod|grep -i simple  
  4. root@ubuntu:~#  
3.最后一种方法就是向initrd内部更新Simple驱动模块,这也是标题的题意。

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

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

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

  1. # List of modules that you want to include in your initramfs.  
  2. # They will be loaded at boot time in the order below.  
  3. #  
  4. # Syntax:  module_name [args ...]  
  5. #  
  6. # You must run update-initramfs(8) to effect this change.  
  7. #  
  8. # Examples:  
  9. #  
  10. # raid1  
  11. # sd_mod  
  12. # Beginning of the block added by the VMware software - DO NOT EDIT  
  13. vmxnet3  
  14. vmw_pvscsi  

# End of the block added by the VMware software

  1. root@ubuntu:~# update-initramfs -u -k 3.13.0  
  1. cp /boot/initrd.img-3.13.0 ~/Desktop/initrd.img-3.13.0.gz

#gunzip ~/Desktop/initrd.img-3.13.0.gz

#cpio -i --make-directories < initrd.img-3.13.0  

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后
  1. # List of modules that you want to include in your initramfs.  
  2. # They will be loaded at boot time in the order below.  
  3. #  
  4. # Syntax:  module_name [args ...]  
  5. #  
  6. # You must run update-initramfs(8) to effect this change.  
  7. #  
  8. # Examples:  
  9. #  
  10. # raid1  
  11. # sd_mod  
  12. # Beginning of the block added by the VMware software - DO NOT EDIT  
  13. vmxnet3   #附注,这里可以看出vmware如何添加vmtools模块  
  14. vmw_pvscsi  
  15. simple_ops_export  
  16. sample  
  17. # End of the block added by the VMware software  

root@ubuntu:~# update-initramfs -u -k 3.13.0  

  1. cp /boot/initrd.img-3.13.0 ~/Desktop/initrd.img-3.13.0.gz

#gunzip ~/Desktop/initrd.img-3.13.0.gz

#cpio -i --make-directories < initrd.img-3.13.0  

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
  1. root@ubuntu:~/Desktop/lib/modules/3.13.0# cd kernel/drivers/char  
  2. root@ubuntu:~/Desktop/lib/modules/3.13.0/kernel/drivers/char# ls  
  3. simple_ops_export.ko  
再次启动进入3.13.0内核查看模块加载结果(去掉/etc/modules文件中的配置,以免影响测试):



  1. root@ubuntu:~# uname -r  
  2. 3.13.0  
  3. root@ubuntu:~# lsmod|grep -i simple  
  4. simple_ops_export       1184  0   
  5. root@ubuntu:~#   
这个结果充分说明了,方法3也是一种不错的方法~~
posted @   愤怒的企鹅  阅读(550)  评论(0编辑  收藏  举报
编辑推荐:
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
阅读排行:
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 零经验选手,Compose 一天开发一款小游戏!
· 一起来玩mcp_server_sqlite,让AI帮你做增删改查!!
点击右上角即可分享
微信分享提示