新聞中心

EEPW首頁(yè) > 嵌入式系統(tǒng) > 設(shè)計(jì)應(yīng)用 > ARM Linux根文件系統(tǒng)Root Filesystem的制作

ARM Linux根文件系統(tǒng)Root Filesystem的制作

作者: 時(shí)間:2016-11-09 來(lái)源:網(wǎng)絡(luò) 收藏
http://xianzilu.spaces.live.com/blog/fakehandlerpage.aspx?wa=wsignin1.0

http://xianzilu.spaces.live.com/blog/cns!4201FDC93932DDAF!290.entry

本文引用地址:http://butianyuan.cn/article/201611/317986.htm

關(guān)于根文件系統(tǒng)的制作,網(wǎng)絡(luò)上有很多文章,大多數(shù)都只講到建幾個(gè)目錄,然后用Busybox做個(gè)Shell,有很多關(guān)鍵的東西沒(méi)有說(shuō)。經(jīng)過(guò)很長(zhǎng)時(shí)間的摸爬滾打,我終于能夠白手起家建立一個(gè)根文件系統(tǒng)了。其實(shí)我也不懂得原理,只是告訴大家我的作法,其中也不免有錯(cuò)誤,歡迎大家指正。

首先介紹根文件系統(tǒng)的組成:目錄、Shell、庫(kù)、腳本,一個(gè)個(gè)來(lái)。
  • 目錄
根文件系統(tǒng)要包含這些必須有的目錄:/dev、/bin、/usr、/sbin、/lib、/etc、/proc、/sys
/dev是devfs(設(shè)備文件系統(tǒng))或者udev的掛在點(diǎn)所在。在使用devfs的內(nèi)核里如果沒(méi)有/dev,根本見(jiàn)不到Shell啟動(dòng)的信息,因?yàn)閮?nèi)核找不到/dev/console;在使用udev的系統(tǒng)里,也事先需要在/dev下建立console和null這兩個(gè)節(jié)點(diǎn)。關(guān)于devfs和udev的區(qū)別,網(wǎng)上很多文章說(shuō)。當(dāng)然如果你的內(nèi)核已經(jīng)不支持devfs了(2.6.12以后),可以使用純純的靜態(tài)節(jié)點(diǎn)。也就是用mknod人工生成。
/bin、/usr/bin、/usr/sbin、/sbin是編譯Busybox這個(gè)Shell時(shí)候就有的,用于存放二進(jìn)制可執(zhí)行文件,就不多解釋了。
/lib用于存放動(dòng)態(tài)鏈接庫(kù)。網(wǎng)上很多文章都說(shuō)靜態(tài)編譯Busybox,可以省去建庫(kù)的麻煩過(guò)程。這樣做只能讓Busybox啟動(dòng),我們自己寫(xiě)的,或者是編譯的軟件包還是需要?jiǎng)討B(tài)庫(kù)的。除非全部靜態(tài)編譯,你可以試試,一個(gè)Hello world就要幾百k。關(guān)于庫(kù)的內(nèi)容后面仔細(xì)說(shuō)。
/etc是用來(lái)存放初始化腳本和其他配置文件的。關(guān)于初始化腳本的內(nèi)容后面仔細(xì)說(shuō)。
/proc是用來(lái)掛載存放系統(tǒng)信息虛擬文件系統(tǒng)——“proc文件系統(tǒng)”,“proc文件系統(tǒng)”在內(nèi)核里面可以選。如果沒(méi)有“proc文件系統(tǒng)”,很多Shell自己的命令就沒(méi)有辦法運(yùn)行,比如ifconfig。“proc文件系統(tǒng)”不像devfs可以自動(dòng)掛載,它需要使用初始化腳本掛載。另外,udev也需要“proc文件系統(tǒng)”的支持。
/sys用于掛載“sysfs文件系統(tǒng)”,“sysfs文件系統(tǒng)”在內(nèi)核里面可以選。目前我認(rèn)為它就是給udev提供支持的,。“sysfs文件系統(tǒng)”也需要使用初始化腳本掛載。
另外還可以有/tmp、/mnt、/swp、/var這樣的不是嵌入式系統(tǒng)必須的目錄,在說(shuō)完Shell的制作之后,我再談建立目錄的事情。
  • Shell
Shell很簡(jiǎn)單,就是Busybox,上網(wǎng)下載一個(gè)來(lái):http://www.busybox.net/downloads/。說(shuō)Busybox和arm-linux-gcc有兼容性問(wèn)題,不過(guò)我覺(jué)得那是比較低版本的時(shí)代問(wèn)題了,我用Busybox 1.8.2和arm-linux-gcc 3.4.1/3.3.2都可以。解壓縮以后找到Makefile里面的ARCH和CROSS_COMPILE,改成:
ARCH ?= arm
CROSS_COMPILE ?= /usr/local/arm/3.4.1/bin/arm-linux-
當(dāng)然CROSS_COMPILE由你自己的編譯器位置決定,然后
# make menuconfig
# make
# make install
注意配置的時(shí)候把一些uCLinux Only的東西去掉,不然會(huì)錯(cuò);配置的時(shí)候還可以修改安裝位置,默認(rèn)是在Busybox下的“_install”。
之后就可以在Busybox生成的Shell基礎(chǔ)上建立根文件系統(tǒng)了,我就用命令來(lái)說(shuō)吧,Busybox在/home/lxz/busybox,根文件系統(tǒng)在/home/lxz/rootfs
# mkdir /home/lxz/rootfs
# cd /home/lxz/busybox/_install
# cp -r ./ /home/lxz/rootfs
# cd /home/lxz/rootfs
# mkdir dev
# mkdir etc
# mkdir lib
# mkdir proc
# mkdir sys
# mkdir tmp
如果不用devfs,下面的命令是必須的。必須以root用戶執(zhí)行(用su命令可以切換為root,切換后用exit命令可以返回普通用戶):
# cd /home/lxz/rootfs/dev
# mknod -m 660 console c 5 1
# mknod -m 660 null c 1 3
如果不使用devfs沒(méi)有這兩個(gè)靜態(tài)節(jié)點(diǎn),console的提示根本就看不到,出現(xiàn)的現(xiàn)象可能是內(nèi)核提示Free init memory: XXK之后,Warning: Unable to find a initial console之類的,具體的單詞記得不是很準(zhǔn)確。我沒(méi)有試過(guò)使用udev的時(shí)候沒(méi)有這兩個(gè)靜態(tài)節(jié)點(diǎn)的情況,反正放了也不影響把/dev掛載為tmpfs。
如果使用udev,還需要把udevd、udevstart、udevadmin這三個(gè)文件放到/sbin里面(我使用udev-117,網(wǎng)上介紹較多的udev-100有9個(gè)文件要放)。
  • 庫(kù)
庫(kù)可是一件非常麻煩的事請(qǐng)。我建議初學(xué)者拷貝買的開(kāi)發(fā)板里面帶的文件系統(tǒng)的庫(kù),如果開(kāi)發(fā)板的文件系統(tǒng)是映像,只需要把映像掛載在某個(gè)目錄下就可以訪問(wèn),假設(shè)映像叫做rootfs.cramfs,可以這樣
# mkdir /home/lxz/evb_rootfs
(切換為root用戶)
# mount -o loop rootfs.cramfs /home/lxz/evb_rootfs
(可以切換為普通用戶)
# cd /home/lxz/evb_rootfs/lib
# cp -r ./ /home/lxz/rootfs/lib
一般開(kāi)發(fā)板里都會(huì)帶有很多庫(kù),但是總體積卻比較大??梢詣h掉一些不用的庫(kù)來(lái)減小體積,但是,,我也不知道那些庫(kù)具體含有什么函數(shù),什么情況刪什么;也許以后我會(huì)把這部分補(bǔ)上。如果覺(jué)得庫(kù)體積太大,也可以自己編譯glibc或者uclibc,但是這是非常繁瑣的事請(qǐng)——目前我認(rèn)為庫(kù)應(yīng)該和編譯器arm-linux-gcc一起制作。有個(gè)傻瓜式的方案是使用cross-tool,下載地址:http://www.kegel.com/crosstool/。雖然cross-tool是用來(lái)制作交叉編譯器的,但是其過(guò)程中生成的glibc卻可以作為副產(chǎn)品為我們所用。cross-tool的使用可以看我之前的這篇文章http://xianzilu.spaces.live.com/blog/cns!4201FDC93932DDAF!274.entry。在成功制作了交叉編譯器之后,就可以從cross-tool的目錄里把glibc取出來(lái),假設(shè)cross-tool的路徑是/home/lxz/cross-tool,編譯出的編譯器叫做arm-linux-gnu-gcc,gcc版本3.4.5,glibc版本2.3.6,想要把glibc庫(kù)拷貝到/home/lxz/glibc,下面的操作還是用命令來(lái)說(shuō)明。
# cd /home/lxz/cross-tool/build/arm-linux-gnu-gcc/gcc-3.4.5-glibc-2.3.6/build-glibc
# ../glibc-2.3.6/configure --prefix=/home/lxz/glibc
# make install
等候安裝結(jié)束
# cd /home/lxz/glibc
# cp -r lib /home/lxz/rootfs
這樣就把glibc的大部隊(duì)拷貝好了,但是這樣還缺兩個(gè)庫(kù),我們繼續(xù)
# cd /home/lxz/cross-tool/build/arm-linux-gnu-gcc/gcc-3.4.5-glibc-2.3.6/build-gcc/gcc
# cp libgcc_s.so* /home/lxz/rootfs/lib
還缺少一個(gè)libtermcap庫(kù),這個(gè)就稍微有些麻煩。libtermcap-2.0.8-35-armv4l源碼包的下載地址是http://www.netwinder.org/mirror/pub/netwinder/SRPMS/nw/9/libtermcap-2.0.8-35.src.rpm,你也可以在這里http://www.netwinder.org/allsrpms.html找到其他版本的。假設(shè)libtermcap-2.0.8-35.src.rpm下載到了/home/lxz/libtermcap,下面繼續(xù)用命令說(shuō)明。
# cd /home/lxz/libtermcap
# rpm2cpio libtermcap-2.0.8-35.src.rpm | cpio -ivd
# tar xvjf termcap-2.0.8.tar.bz2
接下來(lái)要打13個(gè)補(bǔ)丁,很汗啊,請(qǐng)一定按照下面的順序來(lái)打補(bǔ)丁
# patch -p0 -i termcap-2.0.8-shared.patch
# patch -p0 -i termcap-2.0.8-setuid.patch
# patch -p0 -i termcap-2.0.8-instnoroot.patch
# patch -p0 -i termcap-2.0.8-compat21.patch
# patch -p0 -i termcap-2.0.8-xref.patch
# patch -p0 -i termcap-2.0.8-fix-tc.patch
# patch -p0 -i termcap-2.0.8-ignore-p.patch
# patch -p0 -i termcap-buffer.patch
# patch -p0 -i termcap-2.0.8-bufsize.patch
# patch -p0 -i termcap-2.0.8-colon.patch
# patch -p0 -i libtermcap-aaargh.patch
# patch -p0 -i termcap-2.0.8-glibc22.patch
# patch -p0 -i libtermcap-2.0.8-ia64.patch
然后到/home/lxz/libtermcap/termcap-2.0.8里,找到Makefile,修改其中的CC和AR,
CC = /usr/local/arm/3.4.1/bin/arm-linux-gcc
AR = /usr/local/arm/3.4.1/bin/arm-linux-ar
當(dāng)然,你的編譯器在哪里就改成相應(yīng)的內(nèi)容。如果嫌麻煩,可以從本站資料頁(yè)面下載我已經(jīng)打好補(bǔ)丁,修改好Makefile的包,地址http://cosine.oicp.net/project/common/termcap-2.0.8.tar.bz2。需要注意的是,這個(gè)包里CC = arm-linux-gcc、AR = arm-linux-ar,請(qǐng)?jiān)O(shè)置好缺省路徑。然后就可以編譯了:
# cd /home/lxz/libtermcap/termcap-2.0.8
# make
# ln -s libtermcap.so.2.0.8 libtermcap.so.2
# cp libtermcap.so* /home/lxz/rootfs/lib
這樣,Shell啟動(dòng)所需要的基本庫(kù)就都備齊了。但是,這些庫(kù)里面還含有調(diào)試信息,體積稍大,可以把這些信息去掉(當(dāng)然不去掉也沒(méi)有什么影響)。
# cd /home/lxz/rootfs/lib
# arm-linux-strip *.so*
至此,庫(kù)就制作好了。
  • 腳本
有了以上的東西,Shell還是不能正常工作??赡軙?huì)是內(nèi)核提示Free init memory: XXK之后就什么輸出也沒(méi)有了,這時(shí)候向終端敲入文字,可以顯示;就是沒(méi)有終端提示符,不理會(huì)輸入的命令。這是因?yàn)槌跏蓟_本沒(méi)有啟動(dòng)Shell。下面介紹這些腳本。
首先是/etc/inittab。內(nèi)核啟動(dòng)、根文件系統(tǒng)掛載之后所必須的一個(gè)文件,其中列舉了Shell和整個(gè)系統(tǒng)初始化、關(guān)閉所需的命令。如果你想讓Shell出現(xiàn),那么只需要加入這么一行“::askfirst:/bin/ash”。當(dāng)然如果在編譯Busybox的時(shí)候選擇的shell不是“ash”,而是hush、lash、msh之類,那就改成相應(yīng)的東西。除了啟動(dòng)Shell,inittab還干了很多事情,我就用我的inittab來(lái)說(shuō)明了。注意,在編譯Busybox的時(shí)候要選上touch、syslogd、klogd等命令。
# Startup the system
null::sysinit:/bin/mount -o remount,rw /
null::sysinit:/bin/mount -t proc proc /proc
null::sysinit:/bin/mount -a
null::sysinit:/bin/hostname -F /etc/hostname
# Now run any rc scripts
::sysinit:/etc/init.d/rcS
# Now invoke shell
::askfirst:/bin/ash
# Logging junk
null::sysinit:/bin/touch /var/log/messages
null::respawn:/sbin/syslogd -n -m 0
null::respawn:/sbin/klogd -n
# Stuff to do for the 3-finger salute
::ctrlaltdel:/sbin/reboot
# Stuff to do before rebooting
null::shutdown:/usr/bin/killall klogd
null::shutdown:/usr/bin/killall syslogd
null::shutdown:/bin/umount -a -r
null::shutdown:/sbin/swapoff -a
好,把上面這些儲(chǔ)存為inittab,啟動(dòng)系統(tǒng)。應(yīng)該出現(xiàn)兩個(gè)提示,沒(méi)有/etc/fstab和/etc/init.d/rcS。目前我的理解/etc/fstab是用來(lái)執(zhí)行mount -a命令的,里面是文件系統(tǒng)的掛載表。還是用我的fstab來(lái)說(shuō)明。
#
/dev/root / ext2 rw,noauto 0 1
proc /proc proc defaults 0 0
devpts /dev/pts devpts defaults,gid=5,mode=620 0 0
tmpfs /tmp tmpfs defaults 0 0
sysfs /sys sysfs defaults 0 0
還有/etc/init.d/rcS,這在PC上是用來(lái)執(zhí)行/etc/init.d下所有初始化腳本的一個(gè)腳本,,請(qǐng)?jiān)徫也欢迷趺磳?xiě)這種腳本,對(duì)于嵌入式系統(tǒng),根本不需要這么復(fù)雜,直接寫(xiě)在/etc/init.d/rcS里面了。還是用我的/etc/init.d/rcS來(lái)說(shuō)明,其中啟動(dòng)udev的那些指令對(duì)于使用靜態(tài)設(shè)備節(jié)點(diǎn)和devfs的系統(tǒng)不適用。
# Start udev
/bin/mount -t tmpfs tmpfs /dev
/sbin/udevd --daemon
/sbin/udevstart
# Configure net interface
/sbin/ifconfig lo 127.0.0.1 up
/sbin/route add -net 127.0.0.0 netmask 255.0.0.0 lo
/sbin/ifconfig eth0 192.168.2.25 netmask 255.255.255.0
/sbin/route add default gw 192.168.2.1
如果用的是udev,還必須有udev的配置腳本。這個(gè)寫(xiě)起來(lái)有些麻煩,我們可以直接用udev自己帶的那些腳本,位置在udev目錄下的etc/udev/udev.conf和etc/udev/rules.d里面的文件。把這些放到根文件系統(tǒng)中去,etc/udev/udev.conf變?yōu)楦募到y(tǒng)的/etc/udev/udev.conf,etc/udev/rules.d里面的文件變?yōu)?etc/udev/rules.d里面的文件。
至此,一個(gè)可用的最簡(jiǎn)單文件系統(tǒng)就完成了。之后,可以使用mkcramfs、mkyaffs之類的工具制作文件映像,這我就不多說(shuō)了。需要注意的是,cramfs文件系統(tǒng)是只讀的,就算用的是initrd加載的cramfs也一樣是只讀的,這對(duì)根文件系統(tǒng)的/var目錄有一定的影響。除了本文中說(shuō)的辦法,還可以用buildroot這個(gè)工具來(lái)建,但是現(xiàn)在我還在嘗試中,以后再說(shuō)。如果你嫌上面的這一切都很麻煩,可以從本站資料站下載我給Linux 2.6.19內(nèi)核做的最簡(jiǎn)文件系統(tǒng)(1.5M),地址是http://cosine.oicp.net/project/at91rm9200/root.img,cramfs格式映像。


評(píng)論


技術(shù)專區(qū)

關(guān)閉