小男孩‘自慰网亚洲一区二区,亚洲一级在线播放毛片,亚洲中文字幕av每天更新,黄aⅴ永久免费无码,91成人午夜在线精品,色网站免费在线观看,亚洲欧洲wwwww在线观看

分享

initramfs

 enrol 2012-03-30
精通initramfs構(gòu)建step by step
來源: ChinaUnix博客  日期: 2009.06.24 18:19 (共有條評論) 我要評論  
                                               
(一)hello world
一、initramfs是什么
在2.6版本的linux內(nèi)核中,都包含一個壓縮過的cpio格式的打包文件。當(dāng)內(nèi)核啟動時,會從這個打包文件中導(dǎo)出文件到內(nèi)核的rootfs文件系統(tǒng), 然后內(nèi)核檢查rootfs中是否包含有init文件,如果有則執(zhí)行它,作為PID為1的第一個進程。這個init進程負責(zé)啟動系統(tǒng)后續(xù)的工作,包括定位、 掛載“真正的”根文件系統(tǒng)設(shè)備(如果有的話)。如果內(nèi)核沒有在 rootfs中找到init文件,則內(nèi)核會按以前版本的方式定位、掛載根分區(qū),然后執(zhí)行/sbin/init程序完成系統(tǒng)的后續(xù)初始化工作。
這個壓縮過的cpio格式的打包文件就是initramfs。編譯2.6版本的linux內(nèi)核時,編譯系統(tǒng)總會創(chuàng)建initramfs,然后把它與編譯好 的內(nèi)核連接在一起。內(nèi)核源代碼樹中的usr目錄就是專門用于構(gòu)建內(nèi)核中的initramfs的,其中的initramfs_data.cpio.gz文件 就是initramfs。缺省情況下,initramfs是空的,X86架構(gòu)下的文件大小是134個字節(jié)。
二、構(gòu)建第一個initramfs:hello world
從C語言開始,學(xué)習(xí)計算機編程語言的第一個程序幾乎都是hello world,因此我們也構(gòu)建一個最簡單的hello world式的initramfs,以說明initramfs的基本構(gòu)建方法。
initramfs的靈魂是init文件(或者叫程序,因為它會被內(nèi)核第一個執(zhí)行),我們先寫一個簡單的init程序,它會在內(nèi)核的console中打印出經(jīng)典的hello world信息。
hello.c:
#include  
#include  
int main(int argc,char argv[])
{
printf("hello world, from initramfs.\n");
sleep(9999999);
return 0;
}

其中的sleep()函數(shù)語句是為了避免執(zhí)行時內(nèi)核很快打出panic的信息,并非功能上的需要。
接著把hello.c編譯成靜態(tài)連接程序:
gcc -o hello_static -static -s hello.c
命令行中的-s參數(shù)表示編譯后的程序不包含調(diào)試定位信息,目的是減少編譯出來的程序文件的大小。
再創(chuàng)建一個initramfs的構(gòu)建源文件目錄image,把hello_static程序拷入這個目錄,并改名為init。
在image目錄下,創(chuàng)建一個dev/console的設(shè)備文件,否init程序無法在內(nèi)核console中輸出信息:
mknod -m 600 dev/console c 5 1
注意,執(zhí)行這個命令需要有root權(quán)限。
好了,現(xiàn)在可以設(shè)置內(nèi)核配置參數(shù),進行initramfs的構(gòu)建了:
在general setup配置目錄下的initramfs sources配置項下輸入image的路徑名,比如我的路徑就是/home/wyk/initramfs-test/image。因為我們的init程 序是ELF格式的,所以內(nèi)核需要支持ELF的可執(zhí)行文件,否則啟動這個init程序會失敗。在內(nèi)核的 Executable file formats配置目錄下,選擇 kernel support for ELF binaries,則可使內(nèi)核支持ELF格式的可執(zhí)行文件。其他內(nèi)核配置參數(shù)根據(jù)實際需要設(shè)置即可,不過,為了減少內(nèi)核編譯時間,可參考這篇文章
http://linuxman.blog./blog-htm-do-showone-uid-60710-type-blog-itemid-293122.html
設(shè)置一個最簡單的內(nèi)核配置。
內(nèi)核配置參數(shù)設(shè)置完成后,按常規(guī)的內(nèi)核編譯方法進行編譯,initramfs就自動連接到編譯好的內(nèi)核映像文件中了。
三、試驗環(huán)境搭建
試驗initramfs需要經(jīng)常重啟系統(tǒng),所以使用CPU模擬器是不錯的選擇。我們可以選用qemu,它支持直接啟動linux內(nèi)核,無需在模擬器中安裝OS。從方便使用的角度考慮,我們采用qemu launcher設(shè)置qemu的各項參數(shù),它的安裝可參考
http://linuxman.blog./blog-htm-do-showone-uid-60710-type-blog-itemid-612280.html
。
在qemu launcher的linux配置標(biāo)簽中,打勾直接啟動linux,然后在下面的文本框中填上剛才編譯好的內(nèi)核映像文件的路徑名。因為qemu的運行還需要設(shè)置硬盤映像文件,所以還需要在左邊的配置標(biāo)簽中新建一個硬盤映像文件,但實際上我們并不使用硬盤。
配置好qemu的參數(shù)后,點擊launcher按鈕,內(nèi)核就開始在qemu中運行了。內(nèi)核輸出一堆內(nèi)核運行信息后,最后打出了
hello world, from initramfs.
哈哈,我們構(gòu)建的initramfs已經(jīng)能夠正常工作了!
(二)initramfs的前世今生
四、什么是rootfs和ramfs
所有的2.6版本linux內(nèi)核都有一個特殊的文件系統(tǒng) rootfs,是內(nèi)核啟動的初始始根文件系統(tǒng),initramfs的文件會復(fù)制到rootfs。如果把initramfs比作種子,那么rootfs就是 它生長的土壤。大部分linux系統(tǒng)正常運行后都會安裝另外的文件系統(tǒng),然后忽略rootfs。
rootfs是ramfs文件系統(tǒng)的一個特殊實例。ramfs是一種非常簡單的文件系統(tǒng),是基于內(nèi)存的文件系統(tǒng)。ramfs文件系統(tǒng)沒有容量大小的限制,它可以根據(jù)需要動態(tài)增加容量。
ramfs 直接利用了內(nèi)核的磁盤高速緩存機制。所有的文件的讀寫數(shù)據(jù)都會在內(nèi)存中做高速緩存(cache),當(dāng)系統(tǒng)再次使用文件數(shù)據(jù)時,可以直接從內(nèi)存中讀寫,以提 供系統(tǒng)的I/O性能。高速緩存中的寫入數(shù)據(jù)會在適當(dāng)?shù)臅r候回寫到對應(yīng)的文件系統(tǒng)設(shè)備(如磁盤等)中,這時它的狀態(tài)就標(biāo)識為clean,這樣系統(tǒng)在必要時可 以釋放掉這些內(nèi)存。ramfs沒有對應(yīng)文件系統(tǒng)設(shè)備,所以它的數(shù)據(jù)永遠都不會回寫回去,也就不會標(biāo)識為clean,因此系統(tǒng)也永遠不會釋放ramfs所占 用的內(nèi)存。
因為ramfs直接使用了內(nèi)核已有的磁盤高速緩存機制,所以它的實現(xiàn)代碼非常小。也由于這個原因,ramfs特性不能通過內(nèi)核配置參數(shù)刪除,它是內(nèi)核的天然特性。
五、ramfs不是ramdisk
ramdisk 是在一塊內(nèi)存區(qū)域中創(chuàng)建的塊設(shè)備,用于存放文件系統(tǒng)。ramdisk的容量是固定的,不能象ramfs一樣動態(tài)增長。ramdisk需要內(nèi)核的文件系統(tǒng)驅(qū) 動程序(如ext2)來操作其上的數(shù)據(jù),而ramfs則是內(nèi)核的天然特性,無需額外的驅(qū)動程序。ramdisk也象其他文件系統(tǒng)設(shè)備一樣,需要在塊設(shè)備和 內(nèi)存中的磁盤高速緩存之間復(fù)制數(shù)據(jù),而這種數(shù)據(jù)復(fù)制實際不必要的。
六、從ramfs派生的文件系統(tǒng)tmpfs
ramfs 的一個缺點是它可能不停的動態(tài)增長直到耗盡系統(tǒng)的全部內(nèi)存,所以只有root或授權(quán)用戶允許使用ramfs。為了解決這個問題,從ramfs派生出了 tmpfs文件系統(tǒng),增加了容量大小的限制,而且允許把數(shù)據(jù)寫入交換分區(qū)。由于增加了這兩個特性,所以tmpfs允許普通用戶使用。
關(guān)于tmpfs文件系統(tǒng)更多的信息,可以看內(nèi)核源碼中的 Documentation/filesystems/tmpfs.txt 文檔。
綜上所述,initramfs是一種ramfs文件系統(tǒng),在內(nèi)核啟動完成后把它復(fù)制到rootfs中,作為內(nèi)核初始的根文件系統(tǒng),它的任務(wù)是掛載系統(tǒng)真正的根文件系統(tǒng)。這就是initramfs的前世今生。

(三):busybox
七、什么是busybox
busybox號稱是嵌入式Linux中的瑞士軍刀——小巧、功能齊全。它把許多常用的Linux命令都集成到一個單一的可執(zhí)行程序中,只用這一個可執(zhí)行 程序(即busybox)加上Linux內(nèi)核就可以構(gòu)建一個基本的 Linux系統(tǒng)。busybox程序非常小巧,包含全部命令可執(zhí)行文件大小也只有750多K。busybox是完全模塊化的,可以很容易地在編譯時增加、 刪除其中包含的命令。
由于busybox的這些特點,它廣泛應(yīng)用于LiveCD、應(yīng)急修復(fù)盤、安裝盤等系統(tǒng)中。我們也是以它為基礎(chǔ),構(gòu)建initramfs。
八、busybox的配置、編譯和安裝
(1)去
http://
去下載最新的源碼,解壓展開。
(2)用
make menuconfig
命令啟動配置界面配置,配置busybox的特性、選擇要包含在busybox的命令(busybox稱為applet);
也可以用
make defconfig
命令做缺省配置,包含全部的applet。
另外兩個配置命令是
make allyesconfig——最大配置
make allnoconfig——最小配置
它們和make defconfig命令都可以用來作為自定義配置的初始配置,然后再用make menuconfing命令做定制化配置。
為了簡單,我們用make defconfig做缺省配置。
(3)用
make
命令編譯busybox軟件。
(4)用
make CONFIG_PREFIX= install
命令安裝。如果在命令行中省略CONFIG_PREFIX變量的賦值,則會安裝缺省值 ./_install 目錄下。CONFIG_PREFIX可以在make menuconfig的配置界面中修改。
我們用make CONFIG_PREFIX=~/initramfs-test/image 命令把busybox安裝到initramfs的構(gòu)建目錄中。
(5)缺省配置下,busybox動態(tài)鏈接到glibc,所以要把它用到的動態(tài)庫復(fù)制到initramfs的構(gòu)建目錄中。用ldd命令查看busybox用到了哪些動態(tài)庫文件及相應(yīng)的文件路徑,然后把它們復(fù)制到相應(yīng)的目錄下即可。
我們編譯的busybox需要向image/lib目錄下復(fù)制
ld-linux.so.2
libc.so.6
libcrypt.so.1
libm.so.6
動態(tài)庫文件。
九、在image下創(chuàng)建必要的目錄和設(shè)備文件
(1)在imgae目錄下創(chuàng)建
proc , sys , etc ,mnt
四個目錄
(2)hello world 已經(jīng)創(chuàng)建了console 設(shè)備文件,我們再用
mknod -m 600 dev/null c 1 3
命令創(chuàng)建另一個基本的設(shè)備文件。
十、試驗一下
busybox的構(gòu)建和準(zhǔn)備工作做完了,我們試驗一下吧:
在image目錄下以root用戶權(quán)限——
(1)用
mount -vt proc proc =proc
mount -vt sysfs sysfs =sys

命令安裝內(nèi)核虛擬文件系統(tǒng)
(2)用
mount -v -o bind /dev dev
命令綁定/dev的設(shè)備文件到image/dev
(3)用
chroot . /bin/sh
命令進入busybox的環(huán)境。出現(xiàn)shell的命令提示符,可以試著輸入幾個命令,看看執(zhí)行結(jié)果。例如,輸入 fdisk -l 命令看看是否能顯示硬盤的分區(qū)。

(四):mini linux
十一、自動生成/dev下的設(shè)備文件
上節(jié)用chroot方法試驗busybox時,為了簡單,是用“綁定”的方式把主機的/dev中的設(shè)備文件映射到image目錄下的dev目錄。在initramfs上,這種方法顯然不能使用。
生成系統(tǒng)的設(shè)備文件,現(xiàn)在通常都是用udev動態(tài)生成,而initramfs為了做到通用,動態(tài)生成的要求是必須的。在busybox中有一個mdev命令,就是用來動態(tài)生成設(shè)備文件,填充到/dev目錄的。
在系統(tǒng)啟動時,用
mdev -s
命令可以根據(jù)內(nèi)核的sysfs文件系統(tǒng)在/dev目錄中自動生成相應(yīng)的設(shè)備文件。命令執(zhí)行前,需要先掛載內(nèi)核的proc和sysfs虛擬文件系統(tǒng)。
十二、初始身手
解決了自動生成設(shè)備文件的問題后,我們可以試著做一個最簡單的可運行的linux系統(tǒng)了:
(1)在image目錄下寫一個最簡單的init腳本。
#!/bin/sh
mount -t proc proc /proc
mount -t sysfs sysfs /sys
mdev -s
/bin/sh
(2)為init腳本設(shè)置可執(zhí)行權(quán)限,否則內(nèi)核不會去執(zhí)行它。
chmod +x init
(3)有些busybox配置中,mdev命令需要讀取/etc/mdev.conf文件,為了避免出錯信息,我們創(chuàng)建一個空文件。
touch etc/mdev.conf
(4)在內(nèi)核源碼目錄下,執(zhí)行
make
命令,重新編譯內(nèi)核,生成新的initramfs。
好了,在QEMU模擬環(huán)境下啟動這個新的內(nèi)核,系統(tǒng)初始化后,會進入SHELL環(huán)境。在這個SHELL環(huán)境下,試驗一些常用命令,看看是否可以正常運行。
十三、can't access tty
上一步創(chuàng)建的簡單linux系統(tǒng)在進入SHELL環(huán)境時,會打出下面這一句出錯信息:
/bin/sh: can't access tty; job controll off
雖然不影響使用,但終究不夠完美。
產(chǎn)生這個錯誤的原因是我們的SHELL是直接運行在內(nèi)核的console上的,而console是不能提供控制終端(terminal)功能的,所以必須 把 SHELL運行在tty設(shè)備上,才能消除這個錯誤。解決問題的辦法是使用正規(guī)init機制,在執(zhí)行SHELL前打開tty設(shè)備。
另外,這個簡單系統(tǒng)的reboot、halt等命令是不起作用的,也必須通過init方式解決。
十四、busybox的缺省init模式
busybox支持init功能,當(dāng)系統(tǒng)沒有/etc/inittab文件時,它有一套缺省的模式,按下面配置執(zhí)行:
::sysinit:/etc/init.d/rcS
::askfirst:/bin/sh
::ctrlaltdel:/sbin/reboot
::shutdown:/sbin/swapoff -a
::shutdown:/bin/umount -a -r
::restart:/sbin/init

如果busybox檢測到/dev/console不是串口控制臺,init還要執(zhí)行下面的動作:
tty2::askfirst:/bin/sh
tty3::askfirst:/bin/sh
tty4::askfirst:/bin/sh

我們試試這種模式是否可以解決我們的問題。
(1)寫/etc/init.d/rcS腳本
這個腳本實際是要執(zhí)行系統(tǒng)的初始化操作。我們把前面的init腳本改造一下,將最后的/bin/sh命令刪除,然后移到 etc/init.d目錄下,改名為rcS。
(2)initramfs不需要linuxrc,而且如果沒有init文件,內(nèi)核就不認為它是一個有效的initramfs,因而不安裝它,導(dǎo)致內(nèi)核panic。于是,我們在image目錄下,把busybox安裝的linuxrc改名為init
mv linuxrc init
(3)重新編譯內(nèi)核,生成新的initramfs
(4)用QEMU試驗一下新編譯的內(nèi)核。系統(tǒng)啟動后,會打出一句話“please press Enter to active this console”——感覺還不錯。但是按下回車鍵后,系統(tǒng)依然會打出錯誤信息“-/bin/sh:
can't access tty; job controll off ”。用tty命令看看當(dāng)前的終端設(shè)備文件名:
# tty
/dev/console
它還是console,不是tty設(shè)備,所以問題沒有解決。不過,reboot和halt命令倒是可以正常工作了。
經(jīng)過驗證,busybox的缺省init模式無法滿足我們的要求,我們還是要寫inittab,定制自己的init初始化流程。
十五、busybox的inittab文件格式說明
要寫自己的inittab,需要理解busybox的inittab文件格式。
busybox的inittab文件與通常的inittab不同,它沒有runlevel的概念,語句功能上也有限制。inittab語句的標(biāo)準(zhǔn)格式是
:::
各字段的含義如下
:
id字段與通常的inittab中的含義不同,它代表的是這個語句中process執(zhí)行所在的tty設(shè)備,內(nèi)容就是/dev目錄中tty設(shè)備的文件名。由于是運行process的tty設(shè)備的文件名,所以也不能象通常的inittab那樣要求每條語句id的值唯一。
:
busybox不支持runlevel,所以此字段完全被忽略。
:
為下列這些值之一:
sysinit, respawn, askfirst, wait,once, restart, ctrlaltdel, shutdown
其含義與通常的inittab的定義相同。特別提一下askfirst,它的含義與respawn相同,只是在運行process前,會打出一句話 “please press Enter to active this console”,然后等用戶在終端上敲入回車鍵后才運行process。

指定要運行的process的命令行。
十六、寫mini linux的inittab
理解了busybox的inittab格式,我們就可以寫mini linux的inittab:
::sysinit:/etc/init.d/rcS
tty1::askfirst:/bin/sh
tty2::askfirst:/bin/sh
tty3::askfirst:/bin/sh
tty4::askfirst:/bin/sh
tty5::askfirst:/bin/sh
tty6::askfirst:/bin/sh
::restart:/sbin/init
::ctrlaltdel:/sbin/reboot
::shutdown:/bin/umount -a -r
把這個文件放到image的etc目錄下。為了執(zhí)行reboot命令時避免提示找不到/etc/fstab文件,我們再在etc目錄下創(chuàng)建一個空文件
touch fstab
做好了這些,就可以重新編譯內(nèi)核,生成新的initramfs了。在QEMU試驗環(huán)境下驗證新生成的mini linux,系統(tǒng)運行正常,而且象通常的linux系統(tǒng)一樣,用ALT+F1~F6鍵可以在6個終端間切換。

(五)initrd
十七、配置內(nèi)核支持initrd
到目前為止,我們的initramfs都由內(nèi)核編譯系統(tǒng)生成的,并鏈接到內(nèi)核中。其實我們也可以用cpio命令生成單獨的initramfs,與內(nèi)核編譯脫鉤,在內(nèi)核運行時以initrd的形式加載到內(nèi)核,以增加靈活性。
首先配置內(nèi)核使用單獨的initrd:在 Device Driver / Block device / 配置目錄下,選擇 RAM filesystem and RAMdisk ( initramfs/initrd ) support 配置項;再到 General Setup 配置目錄項下,將 initramfs source file(s) 配置項原有的內(nèi)容清空。然后把內(nèi)核源碼樹的usr目錄下已由內(nèi)核編譯生成的initramfs文件initramfs_data.cpio.gz拷貝到 ~/initramfs-test 目錄下,我們先直接用這個文件試驗一下 initrd 方式的initramfs的效果。最后,執(zhí)行make命令重新編譯內(nèi)核后,在QEMU試驗環(huán)境中,把initrd配置框(linux配置框的下面)的內(nèi)容 寫為 ~/initramfs-test/initramfs_data.cpio.gz,指定initrd的文件路徑。
好了,試驗一下新的initrd方式的initramfs吧,效果跟先前的完全一樣。
十八、用cpio命令生成initramfs
cpio 命令有三種操作模式:copy-out、copy-in、copy-pass,生成initramfs用的是它的copy-out模式,即把文件打包的操 作模式。cpio的copy-out操作模式使用 -o 命令行選項指定。缺省情況下,cpio從標(biāo)準(zhǔn)輸入讀取輸入數(shù)據(jù),向標(biāo)準(zhǔn)輸出寫入輸出數(shù)據(jù)。使用 -I 選項可以指定文件名代替標(biāo)準(zhǔn)輸入,使用 -O 選項可以指定文件名代替標(biāo)準(zhǔn)輸出,而 -F 選項指定的文件名則根據(jù)cpio操作模式的不同可代替標(biāo)準(zhǔn)輸入或標(biāo)準(zhǔn)輸出。
把~/initramfs-test/image目錄下的文件打包成initramfs,執(zhí)行下面的命令:
find . | cpio -o -H newc | gzip > ../image.cpio.gz
命令執(zhí)行完畢后,在~/initramfs-test目錄下就會生成文件名為imgae.cpio.gz的initramfs。
上面cpio命令的 -H 選項指定打包文件的具體格式,要生成initramfs,只能用newc 格式,如果使用其他格式,內(nèi)核會打出這樣的出錯信息:Unpacking initramfs... kernel panic - not syncing: no cpio magic
在QEMU試驗環(huán)境下試驗一下新的initrd方式的initramfs,效果跟先前的完全一樣。
十九、cpio命令的其他用法
如果我們要解開一個cpio格式的打包文件,則要使用cpio命令的copy-in操作模式。cpio的copy-out操作模式使用 -i 命令行選項指定。例如,我們想把前一步從內(nèi)核源碼樹 usr目錄下拷貝的initramfs_data.cpio.gz 展開到~/initramfs-test/initramfs_data目錄下,則使用下列命令:
mkdir ~/initramfs-test/initramfs_data
cd ~/initramfs-test/initramfs_data
cpio -i -F ../initramfs_data.cpio.gz --no-absolute-filename
命令執(zhí)行完畢后,initramfs_data目錄下出現(xiàn)多個目錄和文件,用diff命令比較initramfs_data與image目錄,兩者的完全一樣。
上面cpio命令的 --no-absolute-filename 選項的作用是展開文件時,去掉文件路徑最前面的"/",把絕對路徑名變?yōu)橄鄬β窂矫?nèi)核編譯時生成的initramfs使用了絕對路徑名,所以這個選項 必須使用,否則initramfs內(nèi)文件展開到"/"目錄去了,如果你是root用戶或有"/"目錄的寫權(quán)限,那么展開的文件就有可能覆蓋同名的文件(在 文件修改時間新于原有文件),那就糟糕了!
展開文件前,你可能會想先看看打包文件里都有哪些文件,這時就要用 -t 選項了。例如,我們想看看內(nèi)核編譯時生成的initramfs_data.cpio.gz中都有哪些文件,我們就可以用下面的命令:
zcat initramfs_data.cpio.gz | cpio -t
在標(biāo)準(zhǔn)輸出中打出文件名列表。
使用 -v 選項可以在cpio命令執(zhí)行時輸出詳細信息:在打包或展開文件時,輸出已處理的文件名;與 -t 選項連用時,則顯示文件的詳細信息,類似 ls -l 的輸出內(nèi)容。-V 選項則用打點的方式,顯示cpio命令的執(zhí)行進度信息,一個點代表處理一個文件。
(六)switch_root
二十、switch_root 命令
除了基于initramfs的系統(tǒng)(如第四節(jié)的mini linux),通常initramfs都是為安裝最終的根文件系統(tǒng)做準(zhǔn)備工作,它的最后一步需要安裝最終的根文件系統(tǒng),然后切換到新根文件系統(tǒng)上去。以往 的基于ramdisk 的initrd 使用pivot_root命令切換到新的根文件系統(tǒng),然后卸載ramdisk。但是initramfs是rootfs,而rootfs既不能 pivot_root,也不能umount。為了從initramfs中切換到新根文件系統(tǒng),需要作如下處理:
(1)刪除rootfs的全部內(nèi)容,釋放空間
find -xdev / -exec rm '{}' ';'
(2)安裝新的根文件系統(tǒng),并切換
cd /newmount; mount --move . /; chroot .
(3)把stdin/stdout/stderr 附加到新的/dev/console,然后執(zhí)行新文件系統(tǒng)的init程序
上述步驟比較麻煩,而且要解決一個重要的問題:第一步刪除rootfs的所有內(nèi)容也刪除了所有的命令,那么后續(xù)如何再使用這些命令完成其他步驟?busybox的解決方案是,提供了switch_root命令,完成全部的處理過程,使用起來非常方便。
switch_root命令的格式是:
switch_root [-c /dev/console] NEW_ROOT NEW_INIT [ARGUMENTS_TO_INIT]
其中NEW_ROOT是實際的根文件系統(tǒng)的掛載目錄,執(zhí)行switch_root命令前需要掛載到系統(tǒng)中;NEW_INIT是實際根文件系統(tǒng)的init程序的路徑,一般是/sbin/init;-c /dev/console是可選參數(shù),用于重定向?qū)嶋H的根文件系統(tǒng)的設(shè)備文件,一般情況我們不會使用;而ARGUMENTS_TO_INIT則是傳遞給實際的根文件系統(tǒng)的init程序的參數(shù),也是可選的。

需要特別注意的是:switch_root命令必須由PID=1的進程調(diào)用,也就是必須由initramfs的init程序直接調(diào)用,不能由init派生的其他進程調(diào)用,否則會出錯,提示:
switch_root: not rootfs

也是同樣的原因,init腳本調(diào)用switch_root命令必須用exec命令調(diào)用,否則也會出錯,提示:
switch_root: not rootfs
二十一、實踐:用initramfs安裝CLFS根文件系統(tǒng)
現(xiàn)在實踐一下switch_root命令,用它切換一個CLFS的根文件系統(tǒng)硬盤分區(qū)。我的CLFS安裝在/dev/sda8硬盤分區(qū),我們就以此為例說明。
我們還是在以前的image目錄中構(gòu)建
(1)改寫init腳本
#!/bin/sh
mount -t proc proc /proc
mount -t sysfs sysfs /sys
mdev -s
mount /dev/sda8 /mnt (注意:為了簡單,我們直接把CLFS分區(qū)寫死在init腳本中了)
exec switch_root /mnt /sbin/init
(2)生成新的initrd
按上一節(jié)
“精通initramfs構(gòu)建step by step (五):initrd”
描述的cpio命令生成新的initrd。
(3)把新的initrd拷貝到CLFS分區(qū)的/boot目錄下,改名為clfs-initrd
(4)在GRUB的menu.lst配置文件中增加一個啟動項
#test for initramfs of CLFS
title test for initramfs of CLFS (on /dev/sda8)
root (hd0,7)
kernel /boot/clfskernel-2.6.17.13 (注意:并沒有向內(nèi)核傳遞root參數(shù)信息)

initrd /boot/clfs-initrd
全部做完后,重啟機器,選擇 test for initramfs of CLFS 啟動項,機器順利進入了CLFS系統(tǒng),我們構(gòu)建的initramfs用switch_root命令完成了CLFS實際根文件系統(tǒng)的安裝和切換。

(七)modules
二十二、內(nèi)核模塊支持
到目前為止,我們在構(gòu)建initramfs時還沒有涉及內(nèi)核模塊的支持,所用到的硬件驅(qū)動程序都是直接編譯到內(nèi)核中?,F(xiàn)在我們就看看如何使initramfs支持內(nèi)核模塊。
首先,內(nèi)核配置要支持模塊,并支持內(nèi)核模塊的自動加載功能:在內(nèi)核配置菜單中的激活下面的配置項,編譯進內(nèi)核 Load module support / Enable loadable module support / Automatic kernel loading ;
然后把需要的硬件驅(qū)動程序配置模塊形式,比如把我的機器上的硬盤控制器的驅(qū)動編譯成模塊,則選擇
Device Driver
|---->SCSI device support
|---->SCSI disk support
|----->verbose SCSI error reporting (不是必須的,但可方便問題定位)
|----->SCSI low-level drivers
|---->Serial ATA (SATA) support
|---->intel PIIX/ICH SATA support
把它們配置成模塊。
最后,編譯內(nèi)核,并把編譯好的內(nèi)核模塊安裝到image的目錄下:
make
make INSTALL_MOD_PATH=~/initramfs-test/image modules_install
命令執(zhí)行完畢后,在image/lib/modules/2.6.17.13/kernel/drivers/scsi目錄下安裝了4個內(nèi)核模文 件:scsi_mod.ko、sd_mod.ko、ata_piix.ko、libata.ko,它們就是所需的硬盤控制器的驅(qū)動程序。
好了,都準(zhǔn)備好了,可以用cpio命令生成inintramfs了。不過,為了方便后面的試驗,我們再把init腳本改成
#!/bin/sh
mount -t proc proc /proc
mount -t sysfs sysfs /sys
mdev -s
exec /bin/sh
使系統(tǒng)啟動后進入shell環(huán)境,并且用exec調(diào)用的方式,使shell的pid為1,能夠執(zhí)行switch_root命令。
二十三、試驗:用initramfs中的內(nèi)核模塊安裝硬盤文件系統(tǒng)
用新生成的initramfs啟動系統(tǒng),內(nèi)核并沒有自動加載硬盤控制器的驅(qū)動程序,所以 /dev目錄下也沒有sda等硬盤設(shè)備文件。好吧,我們自己加載內(nèi)核模塊文件。不幸的是,busybox的modprobe命令執(zhí)行不正常,不能加載內(nèi)核 模塊。懷疑是busybox的modprobe命令配置或編譯有問題,后續(xù)再花時間定位吧,先用insmod命令依次加載。查看/lib/modules /2.6.17.13/modules.dep,弄清楚了4個模塊的依賴關(guān)系,執(zhí)行下面的命令加載:
insmod scsi_mod
insmod libata
insmod ata_piix
insmod sd_mod
然后再用
mdev -s
命令生成硬盤的設(shè)備文件。
好了,可以安裝CLFS的硬盤分區(qū),并把根文件系統(tǒng)切換到CLFS的硬盤分區(qū):
mount /dev/sda8 /mnt
exec switch_root /mnt /sbin/init
系統(tǒng)正常啟動到了CLFS,我們可以做到用initramfs中的硬盤控制器的驅(qū)動模塊安裝硬盤分區(qū)了。
二十四、mdev的hotplug模式
上面的試驗中,我們在加載完驅(qū)動模塊后調(diào)用了mdev -s 命令來生成硬盤的設(shè)備文件。其實,可以使用mdev的hotplug模式在加載內(nèi)核時自動生成對應(yīng)的設(shè)備文件:
在執(zhí)行insmod命令前,用
echo /sbin/mdev > /proc/sys/kernel/hotplug
命令設(shè)置系統(tǒng)的hotplug程序為mdev。
后續(xù)使用insmod命令加載模塊時,系統(tǒng)自動調(diào)用mdev生成相應(yīng)的設(shè)備文件。
注意:內(nèi)核必須配置支持hotplug功能,而前面提到的CLFS最簡內(nèi)核配置方案是沒有配置hotplug支持的。
(八)coldplug
二十五、udev的coldplug模式
內(nèi)核在啟動時已經(jīng)檢測到了系統(tǒng)的硬件設(shè)備,并把硬件設(shè)備信息通過sysfs內(nèi)核虛擬文件系統(tǒng)導(dǎo)出。udev掃描sysfs文件系統(tǒng),根據(jù)硬件設(shè)備信息生成 熱插拔(hotplug)事件,udev再讀取這些事件,生成對應(yīng)的硬件設(shè)備文件。由于沒有實際的硬件插拔動作,所以這一過程被稱為coldplug。我 們的initramfs就是利用這一機制,加載硬件設(shè)備的驅(qū)動程序模塊。
udev完成coldplug操作,需要下面三個程序:
udevd——作為deamon,記錄hotplug事件,然后排隊后再發(fā)送給udev,避免事件沖突(race conditions)。
udevtrigger——掃描sysfs文件系統(tǒng),生成相應(yīng)的硬件設(shè)備hotplug事件。
udevsettle——查看udev事件隊列,等隊列內(nèi)事件全部處理完畢才退出。
在initramfs的init腳本中可以執(zhí)行下面的語句實現(xiàn)coldplug功能:
mkdir -p /dev/.udev/db
udevd --daemon
mkdir -p /dev/.udev/queue
udevtrigger
udevsettle
許多文檔提到的在udevd --daemon 命令前要執(zhí)行
echo > /proc/sys/kernel/hotplug
命令,經(jīng)驗證,在我們的initramfs環(huán)境下的coldplug功能中并不需要。
二十六、試驗:用udev自動加載設(shè)備驅(qū)動模塊
了解了udev的coldplug的機理,我們就試驗一下用udev自動加載設(shè)備驅(qū)動模塊,并生成硬件設(shè)備文件。
(1)從 /sbin 目錄下拷貝udevd、udevtrigger、udevsettle程序到image目錄下的sbin目錄下,并用ldd命令找到它們所需要的動態(tài)庫文件,拷貝到image目錄下的lib目錄下。
(2)修改init腳本,增加coldplug功能:
#!/bin/sh
mount -t proc proc /proc
mount -t sysfs sysfs /sys
mdev -s
#using udev autoload hard disk driver module
mkdir -p /dev/.udev/db
udevd --daemon
mkdir -p /dev/.udev/queue
udevtrigger
udevsettle
mount /dev/sda8 /mnt
killall udevd
exec switch_root /mnt /sbin/init

注意:在切換到真正根文件系統(tǒng)前,要把udevd進程殺掉,否則會和真正根文件系統(tǒng)中的udev腳本的執(zhí)行相沖突。這就是上面killall udevd 語句的作用。
(3)編寫udev規(guī)則文件
規(guī)則文件是udev的靈魂,沒有規(guī)則文件,udev無法自動加載硬件設(shè)備的驅(qū)動模塊。為了簡單,我們直接使用CLFS中的40- modprobe.rules,把它拷貝到image目錄下的etc/udev/rules.d目錄。有關(guān)udev的規(guī)則文件編寫,已超出了本文的范圍, 后續(xù)我有可能專文描述。
########################################################################
#
# Description : 40-modprobe.rules
#
# Authors : Based on Open Suse Udev Rules
#

kay.sievers@suse.de

#
# Adapted to : Jim Gifford
# LFS : Alexander E. Patrakov
#
# Version : 00.01
#
# Notes :
#
########################################################################

# hotplug
ENV{MODALIAS}=="?*", RUN+="/sbin/modprobe $env{MODALIAS}"

# scsi
SUBSYSTEM=="scsi_device", ACTION=="add", SYSFS{device/type}=="0|7|14", RUN+="/sbin/modprobe sd_mod"
SUBSYSTEM=="scsi_device", ACTION=="add", SYSFS{device/type}=="1", SYSFS{device/vendor}=="On[sS]tream", RUN+="/sbin/modprobe osst"
SUBSYSTEM=="scsi_device", ACTION=="add", SYSFS{device/type}=="1", RUN+="/sbin/modprobe st"
SUBSYSTEM=="scsi_device", ACTION=="add", SYSFS{device/type}=="[45]", RUN+="/sbin/modprobe sr_mod"
SUBSYSTEM=="scsi_device", ACTION=="add", RUN+="/sbin/modprobe sg"

# floppy
KERNEL=="nvram", ACTION=="add", RUN+="load_floppy_module.sh"

注意:上面的
ENV{MODALIAS}=="?*", RUN+="/sbin/modprobe $env{MODALIAS}"
語句是實現(xiàn)自動加載硬件設(shè)備驅(qū)動模塊功能的關(guān)鍵,它根據(jù)sysfs文件系統(tǒng)中記錄 的模塊aliases數(shù)據(jù),用modprobe命令加載對應(yīng)的內(nèi)核模塊。有關(guān)模塊aliases的進一步說明,可參考CLFS手冊(CLFS- 1.0.0-x86)中的11.5.2.4. Module Loading一節(jié)的描述。
(4)拷貝modprobe命令
前一節(jié)提到過,busybox的modprobe 命令不能正常使用,所以我們需要拷貝 /sbin 目錄下的modprobe命令到image目錄下的sbin目錄,供udev加載內(nèi)核模塊使用。再用ldd命令檢查一下 /sbin/modprobe 命令所需的動態(tài)庫文件,如果有則拷貝到image/lib目錄下。(我的檢查結(jié)果是,除了libc6外,不需要其他動態(tài)庫,所以不需要拷貝)
好了,重新生成initramfs,啟動CLFS系統(tǒng),initramfs能夠自動加載硬盤設(shè)備的驅(qū)動模塊,系統(tǒng)順利地從initramfs切換到了真正的CLFS的根文件系統(tǒng)。

(九)內(nèi)核編譯時構(gòu)建initramfs補遺
二十七、直接把cpio打包文件編譯進內(nèi)核
如果我們有一個已經(jīng)做好的cpio格式的initramfs,可以在內(nèi)核編譯時直接編譯進內(nèi)核?;貞浺幌?br> 第一節(jié)
的內(nèi)容,我們在內(nèi)核配置參數(shù)中的initramfs sources配置項下輸入構(gòu)建initramfs的目錄路徑。其實我們也可以直接輸出現(xiàn)成的initramfs的文件名,這樣在內(nèi)核編譯時,就可以把它編譯進內(nèi)核了。
使用這種方法,有兩點需要注意:
(1)cpio文件不能壓縮。一般作為initrd的cpio文件都經(jīng)過了壓縮,所以編譯前需要先把壓縮過的文件解壓。
(2)cpio文件的后綴名必須是 .cpio。內(nèi)核編譯通過 .cpio的后綴名來識別此文件是cpio打包文件,而其他文件后綴名則會被認為是initramfs構(gòu)建的描述文件(關(guān)于描述文件,下面后詳細說明)。
二十八、用描述文件構(gòu)建initramfs
用內(nèi)核編譯工具構(gòu)建initramfs的第三種方法是使用描述文件。在內(nèi)核配置參數(shù)中的initramfs sources配置項下可以輸入initramfs構(gòu)建描述文件的文件名,內(nèi)核編譯工具根據(jù)描述文件完成initramfs的構(gòu)建。
描述文件的語法格式的說明如下:
# a comment
file      
dir     
nod        
slink      
pipe     
sock   

name of the file/dir/nod/etc in the archive
location of the file in the current filesystem
link target
mode/permissions of the file
user id (0=root)
group id (0=root)
device type (b=block, c=character)
major number of nod
minor number of nod

例子:
我們用描述文件的方式,構(gòu)建第一節(jié)中的hello world的initramfs。
hello-init.desp:
dir /dev 0755 0 0
nod /dev/console 0600 0 0 c 5 1
file /init /home/wyk/initramfs-test/hello_static 0755 0 0

在內(nèi)核配置項initramfs sources中指定描述文件hello-init.desp,編譯內(nèi)核時就會生成hello world的initramfs,運行效果與第一節(jié)用指定構(gòu)建目錄的方法構(gòu)建的initramfs的完全相同。
注意:在內(nèi)核幫助文件中,提到initramfs sources配置項可以指定多個目錄或描述文件,內(nèi)核會匯集這些目錄或文件生成一個initramfs。但從我的試驗來看,initramfs sources只接受單一的目錄名或文件名,輸出多個目錄名或文件名(之間用空格分隔),內(nèi)核編譯時就會出錯。也許是我的方法有誤,還望讀者指正。

(十)uclibc
二十九、toolchain
在initramfs中使用uclibc庫,關(guān)鍵是構(gòu)建uclibc的工具鏈toolchain。構(gòu)建uclibc 的 toolchain 有兩種主要方式:(1)用buildroot工具(
http://buildroot./
)自動構(gòu)建,這也是uclibc的官方標(biāo)準(zhǔn)做法。(2)用CLFS Embedded手冊的方法手工創(chuàng)建。目前CLFS Embedded還在開發(fā)中,可在
http:///view/clfs-embedded/x86/
中查閱。
我們簡單地說明用buildroot工具構(gòu)建uclbic的toolchain的步驟:
(1)獲取buildroot。
推薦用svn命令從它的版本庫中下載:
svn co svn:///trunk/buildroot
要求使用svn命令,需要先安裝subversion軟件包。下載過程中,可能會出現(xiàn)連接異常中斷的情況,這時重新執(zhí)行上述命令,繼續(xù)進行下載,有可能要重復(fù)多次。
(2)配置buildroot
因為我們只是創(chuàng)建toolchain,所以需要做相應(yīng)的配置。在buildroot的頂層目錄下,執(zhí)行
make menuconfig
命令,在缺省配置的基礎(chǔ)上做如下配置
Target Architecture: i386
Target Architecture Variant: i686
Package Selection for the target: 取消BusyBox的選項(缺省是選中的)
Target filesystem options: 取消 ext2 root filesystem(缺省是選中的)
Toolchain --> Toolchain type: Buildroot toolchain
(3)編譯
執(zhí)行
make
命令,buildroot工具會自動下載所需要的源文件并自動編譯,等一兩個小時后,toolchain就編譯好了。編譯好的toolchain位于
buildroot/build_i686/staging_dir/usr/bin/
目錄下。工具命令的前綴是 i686-linux- 。
三十、編譯Busybox靜態(tài)連接uclibc庫
一般而言,使用uclibc庫是為了把它靜態(tài)連接到busybox中。具體步驟是:
(1)把uclibc toolchain的目錄添加到PATH中。
在~/.bash_profile文件中添加:
#set PATH so it includes uclibc toolchain if it exist
if [ -d ~/buildroot/build_i686/staging_dir/usr/bin ] ; then
PATH="${PATH}":~/buildroot/build_i686/staging_dir/usr/bin
fi

(2)配置busybox靜態(tài)連接庫。
在busybox的配置界面中,選擇:
Build Options --> Build BusyBox as a static binary (no shared libs)
(3)編譯
執(zhí)行
make CROSS_COMPILE=i686-linux-
命令“交叉編譯”busybox。
最后編譯生成的是靜態(tài)連接的可執(zhí)行文件,不需要在initramfs中拷貝庫文件。
三十一、用buildroot自動構(gòu)建initramfs
buildroot 工具實際是一個功能強大的根文件系統(tǒng)構(gòu)建工具,它以uclibc和busybox作為系統(tǒng)構(gòu)建的基礎(chǔ),toolchain只是它構(gòu)建系統(tǒng)的中間產(chǎn)品。 initramfs是一種特殊的根文件系統(tǒng),當(dāng)然也可以用buildroot工具自動構(gòu)建,下面是構(gòu)建方法的簡要描述:
(1)配置
在buildroot的配置界面下做如下的配置:
Package Selection for the target: 選擇
Busybox
Run Busybox's own full installation

Use minimal target skeleton
Target filesystem options --> cpio the root filesystem --> comprassion method: gzip
(2)編譯
執(zhí)行
make
命令,進行編譯。
(3)輸出
構(gòu)建好的cpio文件是
buildroot/binaries/rootfs.i686.cpio.gz
同一目錄下還包含一個未壓縮的文件:rootfs.i686.cpio
構(gòu)建目錄則是
buildroot/project_build_i686/uclibc/root
可以在這個目錄下對原始的initramfs進行修改調(diào)整,然后自己用cpio命令打包生成新的initramfs。
(4)調(diào)整
直接用buildroot生成的root.i686.cpio.gz作為initramfs,運行時會出現(xiàn)
can't open /dev/tty1: No such file or directory
can't open /dev/tty2: No such file or directory
can't open /dev/tty3: No such file or directory
錯誤信息的循環(huán)輸出,系統(tǒng)不能正常運行。
錯誤的原因是沒有在initramfs的/dev目錄下生成相應(yīng)的設(shè)備文件。需要做如下的調(diào)整:
1)在構(gòu)建目錄(buildroot/project_build_i686/uclibc/root)下的etc/init.d目錄中新增一個初始化腳本文件S10mountfs
#!/bin/sh
mount -t proc proc /proc
mount -t sysfs sysfs /sys
mdev -s

2)更改busybox的setuid屬性,否則無法執(zhí)行mount命令。在構(gòu)建目錄(buildroot/project_build_i686/uclibc/root)下執(zhí)行
chmod -s bin/busybox
命令。
這兩項調(diào)整工作做完后,在構(gòu)建目錄(buildroot/project_build_i686/uclibc/root)下執(zhí)行
find . | cpio -o -H newc |gzip > ../initramfs.cpio.gz
命令,重新生成initramfs的cpio打包文件。
(5)運行效果
運行新的initramfs,系統(tǒng)出現(xiàn)登錄提示。輸入用戶名 root,密碼為空,即可進入一個mini的linux系統(tǒng)。
buildroot是功能強大、配置靈活的自動化構(gòu)建工具,它的詳細使用和配置方法超出了本文的范圍,后續(xù)可能會專文描述,此處就從略了。

    本站是提供個人知識管理的網(wǎng)絡(luò)存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點。請注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點擊一鍵舉報。
    轉(zhuǎn)藏 分享 獻花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多