轉載地址:http://wenku.baidu.com/view/2cb1b4707fd5360cba1adb14.html
-
嵌入式根文件系統制作
轉自:http://wenku.baidu.com/view/2cb1b4707fd5360cba1adb14.html
根文件系統制作
注:busybox下載地址:http://www.busybox.net/
目標:用busybox定制一個很小的文件系統,並且運行用戶編譯的hello。
一、文件系統介紹
二、構建根文件系統
根文件系統制作
注:busybox下載地址:http://www.busybox.net/
目標:用busybox定制一個很小的文件系統,並且運行用戶編譯的hello。
一、文件系統介紹
二、BusyBox介紹
三、實驗步驟
四、分析inittab文件
五、文件系統啟動過程
六、附錄:linux目錄結構
一、文件系統介紹
文件系統:是操作系統用於明確磁盤或分區上的文件的方法和數據結構,即在磁盤上組織文件的方法。Linux文件系統是一個完整的統一體,組織到一個樹形目錄結構中。
Linux遵守文件系統科學分類標准(FHS),一個定義許多文件和目錄的名字和位置的標准。
w 主要規則如下:
l 配置文件放在/etc目錄下
l 設備文件放在/dev目錄下
l 庫文件放在目錄/lib目錄下
l 存放系統編譯后的可執行文件、命令的目錄是/bin、/sbin、/usr/bin、/usr/sbin目錄
在嵌入式系統中,根目錄下的很多目錄都可以刪除,如下:
l 為多用戶提供可擴展環境的所有目錄都應該刪除;如(/home,/mnt,/root)
l 根據引導加載情況,/boot目錄可以刪除。
其余的目錄
l /bin,/dev,/etc,/proc,/sbin,/usr,/lib都是不可缺少的。
二、構建根文件系統
Linux的根文件系統包括支持linux系統正常運行的基本內容,至少應包括以下幾項內容:
l 基本的文件系統結構,如bin、dev、etc、sbin,lib、usr、proc。
l 基本程序運行所需的動態庫。
l 基本的系統配置文件。(自己編寫)
l 必要的設備文件支持。
l 基本的應用程序,如sh、ls、cp等。
構建根文件系統就是往相應的目錄添加相應的文件。如:
l 在/dev添加設備文件,
l 在/etc添加配置文件,(創建)
l 在/bin添加命令或者程序,(選擇)
l 在/lib添加動態庫等。(復制)
添加設備文件
Linux對所有外部設備的訪問都是以文件的形式來進行;
在Linux系統中,可以找到設備對應的文件,稱為設備文件;
設備文件(也叫做設備節點)都存放在/dev的目錄下
w 在/dev目錄下,建立設備文件的命令是mknod;
如:mknod /dev/led c 231 0 (系統分配好的)
上面例子中 “/dev/led”是設備文件路徑;“c”是指定為字符設備;“231”是主設備號;“0”是次設備號。
w Linux系統是靠主、次設備號來聯系驅動程序和設備文件的;
三、BusyBox介紹
Busybox 提供的程序包括:
l 具有shell功能,如csh
l 提供一個迷你的vi編輯器
l 提供系統不可或缺的/sbin/init程序
l 其他的系統基本命令,如:ls,mkdir,ifconfig等。
四、實驗步驟
1、 建立工作目錄(這里建議統一用這個路徑,否則在指定安裝路徑及copy庫文件的路徑都要改)
設定工作目錄為/root/build_rootfs/, 下載busybox到該目錄
2、 建立根目錄, 該目錄就是我們要移植到目標板上的目錄,對於嵌入式的文件系統,根目錄下必要的目錄包括bin,dev,etc,usr,lib,sbin,proc。
cd /root/build_rootfs
mkdir rootfs
cd rootfs
mkdir bin dev etc usr lib sbin proc
mkdir usr/bin usr/sbin usr/lib
(解析各目錄的作用)
/bin bin是Binary的縮寫。這個目錄存放着最經常使用的命令。
/sbin s就是Super User的意思,這里存放的是系統管理員使用的系統管理程序。
/dev dev是Device(設備)的縮寫。該目錄下存放的是Linux的外部設備,在Linux中訪問設備的方式和訪問文件的方式是相同的。
/etc這個目錄用來存放所有的系統管理所需要的配置文件和子目錄。
/usr 我們要用到的很多應用程序和文件幾乎都存放在usr目錄下
/usr/bin存放着許多應用程序;
/usr/sbin存放root超級用戶使用的管理程序;
/usr/lib存放一些常用的動態鏈接共享庫和靜態檔案庫;
/lib這個目錄里存放着系統最基本的動態鏈接共享庫,其作用類似於Windows里的DLL文件。幾乎所有的應用程序都需要用到這些共享庫。
/proc這個目錄是一個虛擬的目錄,它是系統內存的映射,我們可以通過直接訪問這個目錄來獲取系統信息。這個目錄的內容不在硬盤上而是在內存里.
3、 交叉編譯busybox
我們在配置busybox的時候是基於默認配置之上來配置的;先make defconfig就是把busybox配置成默認,然后再make menuconfig來配置busybox。
說明:我們在配置一個源代碼包之前,可以先閱讀源碼包目錄下的README和INSTALL文件以及Makefile的注釋部分,也可以到http://www.busybox.net網站以獲取幫助。
http://www.busybox.net/FAQ.html#configure的第二個問題2 How do I configure busybox?有介紹怎么去配置。
(1)、在/root/build_rootfs解壓
tar -jxvf busybox-1.5.0.tar.bz2
mv busybox-1.5.0 busybox (更名,不是必須的)
cd busybox
(2)、添加交叉工具鏈
export PATH=/usr/local/arm/3.3.2/bin:$PATH
(3)、配置編譯
make defconfig
make menuconfig
配置時,我們基於默認配置,再配置它為靜態編譯,安裝時不要/usr路徑,把Miscellaneous Utilities 下的“taskset”選項去掉,不然會出錯。
如下:
Busybox setting
->builds options
->[*] build busybox as a static binary(a)
->installitation options
->[*] don’t use /usr (b)
Miscellaneous Utilities ―> (c)
[ ] taskset
其他選項都是一些linux基本命令選項,自己需要哪些命令就編譯進去,一般用默認的就可以了。保存退出。
(a)這個選項是一定要選擇的,這樣才能把busybox編譯成靜態鏈接的可執行文件,運行時才獨立於其他函數庫.否則必需要其他庫文件才能運行,在單一個linux內核不能使他正常工作。
(b)這個選項也一定要選,否則make install后,busybox將安裝在原系統的/usr下,這將覆蓋掉系統原有的命令.選擇這個選項后,make install后會在busybox目錄下生成一個叫_install的目錄,里面有busybox和指向他的鏈接.
4、編譯安裝
make ARCH=arm CROSS_COMPILE=arm-linux- CONFIG_PREFIX=/root/build_rootfs/rootfs all install
(此時bin(195個 290M) sbin(58個 86.4M) 已安裝了文件,其實是busybox的可執行文件和指向它的鏈接。不同的鏈接名完成不同的功能,命令行調用作為一個參數傳給busybox,即可完成相應的功能)
ARCH指定平台
CROSS_COMPILE指定交叉編譯
CONFIG_PRRFIX指定安裝的路徑
由於/root/build_rootfs/rootfs/linuxrc 和/root/build_rootfs/rootfs/sbin/init 是同一個程序,可以把linuxrc刪除,以節省空間。
此時U-BOOT啟動參數應該設為:(板上uboot啟動時再執行)
Setenv bootargs root=/dev/mtdblock2 init=/sbin/init console=ttySAC0,115200 display=sam320 men=64M devfs=mount
如果不rm linuxrc,則 init=/linuxrc
也可以先rm linuxrc,再手寫腳本 linuxrc。通過linuxrc中執行“exec /sbin/init”來執行sbin/init。
5、 copy C庫
交叉應用程序的開發需要用到交叉編譯的鏈接庫,交叉編譯的鏈接庫是在交叉工具鏈的lib目錄下;我們在移植應用程序到我們的目標板的時候,需要把交叉編譯的鏈接庫也一起移植到目標板上,這里我們用到的交叉工具鏈的路徑是/usr/local/arm/3.3.2/,所以鏈接庫的目錄是/usr/local/arm/3.3.2/lib(本來跟目標板相關的目錄是/usr/local/arm/3.3.2/arm-linux, 因此要拷貝的鏈接庫應該在/usr/local/arm/3.3.2/arm-linux/lib下,但是此目錄的很多鏈接都是鏈接到/usr/local/arm/3.3.2/lib目錄下的庫文件,所以我們從/usr/local/arm/3.3.2/lib目錄拷貝庫),此目錄下有四種類型的文件(其實就2種:.so動態庫 .a靜態庫):
(1) .so動態庫(了解)
A、實際的共享鏈接庫(libname-version.so)
如:libc-2.3.2.so
B、主修訂版本的符號鏈接. (lib.so.version)
程序一旦鏈接了特定的鏈接庫,它將會使用其符號鏈接,程序啟動時,加載器在加載程序之前,會加載該文件。
如:libc.so.6
C、與版本無關的符號鏈接(libname.so)
這些符號鏈接的只要功能是為需要鏈接特定的鏈接庫的所有程序提供一個通用的條目,與版本號無關。
如:libc.so
(2) .a靜態庫
靜態鏈接庫包文件
如:libc.a
(1)、進入鏈接庫目錄
cd /usr/local/arm/3.3.2/lib
編寫一個shell文件,用於copy實際的共享鏈接庫;主修訂版本的符號鏈接;動態連接器及其符號鏈接到目標板根目錄下的lib。
w 主要的動態鏈接庫:
ld 動態鏈接器
libc 主C鏈接庫
libcrypt 秘密學鏈接庫
libdl 用來動態加載共享文件的動態庫
libm 數學庫
libpthread多線程庫
還可以通過arm-linux-readelf命令來找出應用程序依賴於哪些動態鏈接庫;
如:arm-linux-readelf -d hello; //hello只是打印一句“hello”的程序;
(2)、vi cp.sh
內容如下:
(僅供參考,可以自己寫)
for file in libc libcrypt libdl libm libnss_dns libnss_files libpthread libresolv libutil
do
cp $file-*.so /root/build_rootfs/rootfs/lib (1)
cp -d $file.so.[*0-9] /root/build_rootfs/rootfs/lib (2)
done
cp -d ld*.so* /root/build_rootfs/rootfs/lib (3)
cp -d libgcc_s*.so* /root/build_rootfs/rootfs/lib /*標准C庫*/
cp -d libstdc++.so* /root/build_rootfs/rootfs/lib
cp -d libuuid.so* /root/build_rootfs/rootfs/usr/lib
cp -d libz.so* /root/build_rootfs/rootfs/usr/lib
cp -d libpng*.so* /root/build_rootfs/rootfs/usr/lib
cp -d libjpeg.so* /root/build_rootfs/rootfs/usr/lib /*解碼庫*/
(-d 保持原來的鏈接屬性)
(3)、保存退出
(1)第一個cp命令會復制實際的共享庫
(2)第二個cp命令會復制符號鏈接本身
(3)第三個cp命令會復制動態連接器及其符合鏈接
(4)、執行剛編寫的shell。
source cp.sh
( lib(20個 61.9M) usr/lib(9個 639K) 安裝了文件)
這樣就把鏈接庫復制過來了。
(5)、接着我們還要縮小復制過來的鏈接庫的體積,如下:
arm-linux-strip –s /root/build_rootfs/rootfs/lib/lib* (根據具體情況修改)
(lib由61.9M 變為5.64M)
6、 建立配置文件
這里我們沒有添加inittab(執行順序)等文件,我們只是添加了一個c shell初始化時讀取的文件。
內核啟動的最后,會執行sbin/init程序,init程序在啟動的最后會執行/bin/sh,sh在啟動的時候會讀取文件。
我們在/etc/profile文件里設定PATH,LD_RARYLIB_PATH環境變量,目的是配置用戶程序運行的環境。
cd /root/build_rootfs/rootfs/etc
vi profile
內容如下
#!/bin/sh
echo "Set seaech library in /etc/profile"
export LD_LIBRARY_PATH=/lib //定義查找可用共享對象的位置 //usr/lib
echo "Set user path in /etc/profile"
export PATH=/bin:/sbin:/usr/bin //命令的路徑
保存退出
7、 添加一個用戶程序
進入工作目錄
cd /root/build_rootfs/
編輯源文件
vi hello.c
內容如下
#include <stdio.h>
main()
{
printf(“welcome to my rootfs\n”);
}
保存退出
交叉編譯
arm-linux-gcc hello.c –o hello(下載到目標板的話必須交叉編譯)
復制到目標板的根目錄
mv hello /root/build_rootfs/rootfs/usr/bin
8、 制作cramfs映像
找到mkcramfs工具(該工具只能制作可讀的鏡像文件,而mkfs.jffs2工具或以把文件系統制作成可讀可寫的鏡像文件),把它復制到“/root/build_rootfs”目錄下。
cd /root/build_rootfs/
./mkcramfs rootfs rootfs.cramfs
rootfs.cramfs就是我們要燒寫到目標板的映像文件
9、燒寫rootfs.cramfs到3分區,啟動開發板,運行hello程序。
將rootfs.cramfs文件拷貝到tftp下載的目錄下,如拷貝到linux 系統中的/tftpboot目錄;
開發板的u-boot通過tftp命令下載;
根據分區表來燒寫;
10、U-BOOT下載和燒寫:
燒寫內核
tftp 30008000 zImage
nand erase 0x40000 0x1c0000
nand write 30008000 0x40000 0x1c0000
燒寫根文件系統
tftp 30008000 rootfs.cramfs
nand erase 0x200000 0x1e00000
nand write 30008000 0x200000 0x1e00000
11、啟動:
setenv bootargs root=/dev/mtdblock2 init=/sbin/init console=ttySAC0,115200 display=sam320 men=64M devfs=mount
setenv bootcmd nand read 0x30008000 0x40000 0x1c0000 \;go 0x30008000
saveenv
reset
等待5秒鍾,自動運行linux系統。
12、通過NFS掛載:
setenv bootargs root=/dev/nfs nfsroot=192.168.11.58:/home/gec2440 ip=192.168.11.56 init=/sbin/init console=ttySAC0,115200 display=sam320
另,還得開通NFS服務和設置要掛載的目錄共享(系統-管理-服務器設置-NFS,在用戶“user access”卡中勾選第一項)
五、分析inittab文件4
Inittab文件中每一行的格式如下:
id:runlevel:action:process
其中:
l Id:用來指定所啟動進程的控制台,在嵌入式系統中一般不添加;
l Runlevel:運行級別;
l Action:指出init程序在執行相應process時,對process所采取的動作
l Process:具體的執行程序;
inittab文件的action字段中,有以下八個應用到process的動作:
l Sysinit: 為init提供初始化命令行的路徑;
l Respawn: 當該進程死亡時,init將重新啟動該進程,不等待該 進程的結束;
l Askfirst: 當相應的進程終止便重新啟動,會在控制台顯示 “Please press Enter to activate this console.”的信息。
l Wait: 啟動進程並等待其結束;
l Once: 啟動相應的進程,但不等待該進程結束;
l Ctrlaltdel: 當按下Ctrl-Alt-Delete組合鍵時,執行相應的進程;
l Shutdown: 當系統關機時,執行相應的進程;
l Restart: init從新啟動時,執行相應的進程。
六、文件系統啟動過程
-----------------簡單的rootfs的啟動過程:
init=/linuxrc是二進制文件 ,而linuxrc是/sbin/init 的鏈接文件,它會去讀取配置文件/rootfs/etc/profile或者inittab ,然后進入shell控制台。
------ 以gec2440文件系統做講解 su 2009 -03 -09 ------------
1 init=/linuxrc 根目錄的,
2 exec /sbin/init init 是個2進制文件,init程序需要讀取配置文件/etc/inittab
3 inittab是一個不可執行的文本文件,它有若干行指令所組成。
/etc/inittab 文件中:
# This is run first except when booting
::sysinit:/etc/init.d/rcS //啟動時自動執行/etc/rc.d/rc.sysinit腳本 4
# Start an "askfirst" shell on the console
#::askfirst:-/bin/bash
::askfirst:/bin/bash //類似於respawn,主要用途是減少系統上執行的終端應用程序的數量,會在控制台上顯示“please press enter to active this console”,等待用戶按下”Enter ”鍵。
# Stuff to do when restarting the init process
::restart:/sbin/init //重啟時執行
#::once:/sbin/raja.sh
::once:/usr/etc/rc.local //啟動相應的進程,但不等待該進程結束 5
# Stuff to do before rebooting
::ctrlaltdel:/sbin/reboot //在啟動過程中允許按CTRL-ALT-DELETE重啟系統
::shutdown:/bin/umount -a –r //重啟時執行
4 /etc/init.d/rcS 完成一些系統初始化的工作 ,主要完成的工作有:激活交換分區,檢查磁盤,加載硬件模塊以及其它一些需要優先執行任務。
其 中:
/bin/mount –a 實際上是把 /etc/fstab 中的設備 mount 過去。
(-a Mount all filesystems (of the given types) mentioned in fstab.)
5 接着執行 /usr/etc/rc.local
這里執行一些初試初始化腳本,配置IP等,創建目錄。
最后執行根目錄的 testshell
6 在testshell 里執行 /project/PMP/src/pmp 即我們的應用程序。
cd /project/PMP/src
exec ./pmp -qws
七、附錄:linux目錄結構
/bin bin是Binary的縮寫。這個目錄存放着最經常使用的命令。
/boot這里存放的是啟動Linux時使用的一些核心文件,包括一些鏈接文件以及鏡像文件。(BIOS自檢->MBR(GRUB)->KERNEL->KERNEL自解壓->內核初始化->內核啟動)/dev dev是Device(設備)的縮寫。該目錄下存放的是Linux的外部設備,在Linux中訪問設備的方式和訪問文件的方式是相同的。
/etc這個目錄用來存放所有的系統管理所需要的配置文件和子目錄。
/home用戶的主目錄,在Linux中,每個用戶都有一個自己的目錄,一般該目錄名是以用戶的賬號命名的。
/lib這個目錄里存放着系統最基本的動態鏈接共享庫,其作用類似於Windows里的DLL文件。幾乎所有的應用程序都需要用到這些共享庫。
/lost+found這個目錄一般情況下是空的,當系統非法關機后,這里就存放了一些文件。
/mnt在這里面中有四個目錄,系統提供這些目錄是為了讓用戶臨時掛載別的文件系統的,我們可以將光驅掛載在/mnt/cdrom上,然后進入該目錄就可以查看光驅里的內容了。
/proc這個目錄是一個虛擬的目錄,它是系統內存的映射,我們可以通過直接訪問這個目錄來獲取系統信息。這個目錄的內容不在硬盤上而是在內存里,我們也可以直接修改里面的某些文件,比如可以通過下面的命令來屏蔽主機的ping命令,使別人無法ping你的機器:
echo 1 > /proc/sys/net/ipv4/icmp_echo_
ignore_all。
/root該目錄為系統管理員,也稱作超級權限者的用戶主目錄。
/sbin s就是Super User的意思,這里存放的是系統管理員使用的系統管理程序。
/tmp這個目錄是用來存放一些臨時文件的。
/usr 我們要用到的很多應用程序和文件幾乎都存放在usr目錄下。具體來說:
/usr/X11R6存放X-Windows的目錄;
/usr/games存放着XteamLinux自帶的小游戲;
/usr/bin存放着許多應用程序;
/usr/sbin存放root超級用戶使用的管理程序;
/usr/doc Linux技術文檔;
/usr/include用來存放Linux下開發和編譯應用程序所需要的頭文件;
/usr/lib存放一些常用的動態鏈接共享庫和靜態檔案庫;
/usr/local這是提供給一般用戶的/usr目錄,在這里安裝一般的應用軟件;
/usr/man幫助文檔所在的目錄;
/usr/src Linux開放的源代碼,就存在這個目錄,愛好者們別放過哦;
/var這個目錄中存放着在不斷擴充着的東西,我們習慣將那些經常被修改的目錄放在這個目錄下。包括各種日志文件。如果你想做一個網站,你也會用到/var/www這個目錄。