天天看點

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

#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

[email protected]:~# uname -r
3.13.0-32-generic
[email protected]:~# cat /etc/issue
Ubuntu 12.04.5 LTS \n \l
           
[email protected]:~# cd ~/Desktop/linux-3.13/
[email protected]:~/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内部更新驅動子產品
[email protected]:~# lsmod|grep -i simple
simple                   799  0 
simple_ops_export       1184  1 simple
[email protected]:~# uname -r
3.13.0
           

但是如果進入Ubuntu, with Linux 3.13.0-32-generic,則系統引導後lsmod的結果中不會有Simple子產品,因為/lib/modules/(`uname -r`)/kernel/driver下根本不存在這個子產品

[email protected]:~# uname -r
3.13.0-32-generic
[email protected]:~# lsmod|grep -i simple
[email protected]:~#
           

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>
           
[email protected]:~# 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">[email protected]:~/Desktop# cd lib/modules/3.13.0/
[email protected]:~/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">[email protected]:~# 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">[email protected]:~/Desktop# cd lib/modules/3.13.0/
[email protected]:~/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

[email protected]:~/Desktop/lib/modules/3.13.0# cd kernel/drivers/char
[email protected]:~/Desktop/lib/modules/3.13.0/kernel/drivers/char# ls
simple_ops_export.ko
           

再次啟動進入3.13.0核心檢視子產品加載結果(去掉/etc/modules檔案中的配置,以免影響測試):

制作initrd(1):向initrd内部更新驅動子產品
[email protected]:~# uname -r
3.13.0
[email protected]:~# lsmod|grep -i simple
simple_ops_export       1184  0 
[email protected]:~# 
           

這個結果充分說明了,方法3也是一種不錯的方法~~

繼續閱讀