更新「Building ARM9 Bootstrap Root Filesystem」教學文件,在此提供與各位朋友分享,並請多多指正,以讓文件內容更加完善。以下文件以 MS-Word 轉檔,請多見諒。
《Jollen的Root Filesystem建置技術系列》
製作ARM9的Bootstrap
Root
Filesystem
更新日期:2007/1/23
在「完整註明出處」的前提下(註明方式說明),您能立即擁有轉貼與引用的授權,且毋需知會作者。
目的
製作 bootstrap root filesystem(base root filesystem)以提供一個最簡單、陽春且可開機的環境;製作完成的系統可開機到shell模式,並可使用
busybox 提供的指令。
準備工作
首先,您必須準備一台 host 開發環境,並安裝好 cross toolchain;接著,由於本文是做實機測試,因此,如果您沒有 ARM9 開發板,可以考慮使用 Qemu 來做模擬測試。
以下的操作示範,只節錄重點指令片段,您可能必須根據自己的整體實作流程,來微調指令的順序,或是參數等。
Step 1:建立工作目錄
建立一個專用的工作目錄,命名為 arm9.so-busybox/:
# mkdir arm9.so-busybox/
# cd arm9.so-busybox/
接著在 arm9.so-busybox/ 目錄下建立 4 個子目錄:
# mkdir src/
install/ mnt/ pub/ build/
實際進行 root filesystem
實作時,我們應該養成將檔案分類擺放的好習慣。以本專案為例,build/ 目錄用來編譯程式,src/ 目錄用來存放原始程式碼,install/ 目錄則用來擺放我們最後的 root filesystem。
Step 2:建立目錄架構
根據 FHS 的目錄架構標準,在 root filesystem 目錄下(install/)建立目錄階層架構:
# cd install/
# mkdir bin/ dev/ etc/ mnt/ proc/ sbin/ usr/
另外還有二個必要的目錄:/var 與 /tmp,由於這二個目錄都需要具備寫入權限,所以在這裡我們是以 ramdisk 的做法來 mount 這二個目錄。
Step 3:建立裝置檔
在 root filesystem
的 dev/ 目錄下建立必要的裝置檔:
crw------- 1 root root 5, 1 1月 1 1970 console
crw------- 1 root root 29, 0 1月 1 1970 fb0
crw------- 1 root root 1, 3 1月 1 1970 null
brw------- 1 root root 1, 0 1月 1 1970 ram0
crw------- 1 root root 5, 0 1月 1 1970 tty
crw------- 1
root root 4, 0 1月 1 1970 tty0
此階段使用 mknod 指令來完成。請先切換到 root filesystem 的 dev/ 目錄下,接著執行以下指令:
# mknod console c 5 1
# mknod fb0 c 29 0
# mknod null c 1 3
# mknod ram0 1 0
# mknod tty c 5 0
# mknod tty0 c 4 0
對於需要產生大量 device file 的場合來說,可以改用 genext2fs 的 ‘-D’ 參數來製作。詳見 Jollen’s Blog:[使用 genext2fs 的 '-D'(device file table)來建立 root filesystem]。
Step 4:加入Busybox
編譯並安裝 Busybox(動態程式庫方式)。將取得的Busybox原始碼解壓縮至 project 目錄裡的 src/ 子目錄下,以下是幾個注意事項:
本教學文件使用 Busybox 1.3.1
Busybox 1.3.0
開始,使用
Linux Kernel
的 Makefile(因為開始支援
CONFIG_DESKTOP)。Cross compile
時,需要修改
Makefile
如下:
ARCH ?= arm
CROSS_COMPILE ?= /opt/crosstool/gcc-3.4.1-glibc-2.3.3/arm-9tdmi-linux-gnu/bin/arm-9tdmi-linux-gnu-
CROSS_COMPILE 的設定是 cross toolchain 的「PREFIX」,視您的 toolchain 而定。您可由
http://www.jollen.org/kit/
下載本文所使用的 GCC 3.4.1 ARM9 toolchain,以使用與本文完全相同的修改。
Busybox 整合了常用的指令與工具,我們可以設定 Busybox,以勾選我們需要的功能選項。進入 Busybox 的設定選單:
# make menuconfig
接著直接進行編譯(cross compile):
# make
# make install
Step 5:加入動態程式庫
˙ libc.so.6:C library標準程式庫。
˙ ld-linux.so.2:Native dynamic loader。
# cd ../../install (切換至root filesystem根目錄)
# cp /opt/crosstool/gcc-3.4.1-glibc-2.3.3/arm-9tdmi-linux-gnu/arm-9tdmi-linux-gnu/lib/ld-linux.so.2 lib/ (複制native dynamic loader。以上命令請勿斷行)
# cp /opt/crosstool/gcc-3.4.1-glibc-2.3.3/arm-9tdmi-linux-gnu/arm-9tdmi-linux-gnu/lib/libc.so.6 lib/ (複製C library。以上命令請勿斷行)
Step 6:加入系統檔案
加入2個重要的系統檔案於 etc/ 目錄下:
˙ fstab:mount table。
˙ inittab:系統初始表(init
table)。
etc/fstab內容如下:
/dev/ram0 / ext2 defaults 1 1
none /proc proc defaults 0 0
/dev/ram1
/tmp ramfs defaults 0 0
/dev/ram2
/var ramfs defaults 0 0
fstab
第一行設定,目的在將 /dev/ram0 重新附掛成
‘/’(root),此動作用意在於重新指定
‘/’ 的檔案系統為 ext2。最後二行的目的是為了以 ramfs 來 mount 重要的二個目錄:/var 與 /tmp;如此一來,就算開機沒做 remount root(詳見後文說明),也能對
/tmp 與 /var 目錄做寫入的動作
etc/inittab內容如下:
:0:sysinit:/etc/rc.d/rc.init
:0:respawn:/bin/sh
根據這個 inittab 設定,當系統開機後便會進入
run level 0,在
run level 0 模式下,init process會執行2個動作:(1) 執行 /etc/rc.d/rc.init,此即「init
script」;(2) 執行 /bin/sh,即進入 shell
模式。
在此我們並沒有參照 LSB 的標準來設定 run
level,而且也沒有使用
getty 來讓使用者登入(多使用者模式)。
Step 7:編寫 Initial Script
根據 inittab 的設定,我們
root filesystem 的 init script 位於 /etc/rc.d/rc.init。以下提供一個供 Embedded Linux 使用的 init script 範本:
#!/bin/sh
# automount (/etc/fstab)
mount -a
# remount root
mount -o remount
rw /
#
mkdir /var/lock
mkdir /var/lock/subsys
mkdir /var/run
# start other applications (Running application automatically during
# booting up.
# eg. /bin/thttpd –p 80 –d /var/www
# mount -o remount rw /
此動作的目的是將 root(’/’)重新
mount 成可讀寫,此動作是選擇性的,若省略不做,請務必保持
/var 與 /tmp 目錄是能寫入的(建議以 ramdisk 方式實作為佳)。
若 root filesystem
未包含 inittab 設定檔,則 Busybox 會使用以下的內建設定:
::sysinit:/etc/init.d/rcS
::askfirst:/bin/sh
::ctrlaltdel:/sbin/reboot
::shutdown:/sbin/swapoff -a
::shutdown:/bin/umount -a -r
::restart:/sbin/init
不過,還是建議編寫自己的 inittab
設定檔。
Step 8:製作 Root Filesystem 映像檔(Image File)
截至目前為止,我們的檔案系統已經擁有基本的系統指令與工具。接下來,我們即可將建置完成的 root filesystem 製作成 ext2 格式的映像檔。
以下提供二種 ext2fs image file 的製作方式:(1)
土方法;(2) 使用 genext2fs 工具。
先說明傳統的土方法。首先,先利用dd指令做出一個空白的檔案,大小為 4M(bytes):
# dd if=/dev/zero of=ext2fs bs=1k count=4096
我們將檔案命名為 ext2fs,接著再將
ext2fs 製作成 ext2
格式的檔案系統:
# mkfs.ext2 ext2fs
mke2fs 1.32(09-Nov-2002)
ext2fs is not a block special device.
Proceed
anyway?(y,n)y
選擇y後出現以下畫面:
Filesystem label=
OS type: Linux
Block size=1024(log=0)
Fragment size=1024(log=0)
128 inodes, 1024 blocks
51 blocks(4.98%)reserved for the super user
First data block=1
1 block group
8192 blocks per group, 8192 fragments per group
128 inodes per group
Writing inode tables: done
Writing superblocks and filesystem accounting information: done
This filesystem will be automatically checked every 26 mounts or
180
days, whichever comes first. Use tune2fs -c or -i
to override.
到這裡我們已經做好一個檔案格式為 ext2 的空白映像檔,再來只要將先前做好的 root filesystem 全部複製到 ext2fs 映像檔「裡面」即可。
先將 ext2fs 附掛至任一空目錄,例如
mnt/:
# mkdir mnt/
# mount
-t ext2 -o loop ext2fs mnt/ (指定檔案系統為 ext2)
複製檔案系統時,我們不使用 cp 指令,而是利用 tar 來完成:
# cd install/
# tar cz * > ../install.tar.gz (將檔案系統做成tarball,同時也備份 root filesystem。)
# cd ..
# cd mnt/
# tar zxvf ../install.tar.gz
(再將tarball解至映像檔)
接著將映像檔 umount 並壓縮即可:
# cd ..
# umount mnt/
# gzip -9c ext2fs > pub/ext2fs.gz
最後得到的 ext2fs.gz 即是完成品。請注意,若不使用 tar 來說,也應該使用 cpio 來複製檔案,避免使用
cp 指令。
使用 genext2fs
genext2fs 是一個 ext2 filesystem image file 的製作工具,可以讓我們很方便地將 root filesystem 製作成 image 檔。請由 genext2fs
的官方網站下載原始碼套件:
http://genext2fs.sourceforge.net/
編譯後可以取得 genext2fs 檔案,以下是將 install/ 目錄製作成 ext2fs image 檔的指令:
# genext2fs
-b 8192 -i 1024 -d install/ ext2fs
執行後,會得到檔名為 ext2fs 的 image
檔,大小為 8 MB(透過 ‘-b’ 參數指定 image file 大小);接著同樣再用
gzip 將 ext2fs 檔壓縮即可。
Step 9:在 Target 端做測試
本步驟以 Jollen-Kit!
為例,Jollen-Kit! 是由 www.jollen.org 所推出的 ARM9 training board,詳細介紹請參考 [http://www.jollen.org/kit/]。請注意,本階段的操作,視 target device 的不同而不同,因此以下示範只適用於 Jollen-Kit! 或是其他的 SMDK2410 平臺。
步驟 8 所得到的 ext2.gz 必須再包裝成 U-Boot 的格式,才能透過 U-Boot 載入到
RAM,以成為 kernel 的 initial ramdisk(initrd):
# mkimage -A arm -O linux -T ramdisk -C none -a
0x30800000 -e 0x30800000 -n ramdisk -d ext2fs.gz urootfs.img
執行後可得到 urootfs.img 檔案,在測試階段為了方便起見,我們可以直接將 urootfs.img 載到 RAM 做測試;U-Boot 指令如下:
jollen.org
# tftpboot 32000000 urootfs.img;
tftpboot 30F00000 uimage.img;
bootm 30F00000 32000000
urootfs.img 是我們製作的 root filesystem,uimage.img 則是給 Jollen-Kit! 使用的 Linux kernel(pre-built)。
延伸閱讀
2006.10.03: Library Dependency 的議題要點
Jollen's Blog 使用 Github issues 與讀者交流討論。請點擊上方的文章專屬 issue,或 open a new issue
您可透過電子郵件 jollen@jollen.org,或是 Linkedin 與我連絡。更歡迎使用微信,請搜尋 WeChat ID:jollentw