第一章 前言 目的 本文的目的,是講述嵌入式Linux系統的建立、開發的一般過程。制作一個小型的Linux的系統,可以移植至其它硬盤、軟盤、優盤、flash rom……
關於作者 九賤,E名kendo,喜歡網絡入侵技術、防火牆、入侵檢測技術及網絡技術,對Linux也頗感興趣,想認識有共同愛好的朋友。最近閒暇,把一些學過的東西寫下來,總結總結,以作備忘這需。已完成的有《網絡入侵檢測設計與Snort2.2源碼分析》和這篇《我也來學做嵌入式Linux》。正在進行中的有《Windows防火牆技術實現大全》和《Linux防火牆實現及源碼分析》。大家可以在CU上,或者是到我的小站www.skynet.org.cn上與我交流
做一個嵌入式Linux系統究竟要做哪些工作 做一個嵌入式Linux系統究竟需要做哪些工作?也就是本文究竟要講述哪些內容?我先介紹一個脈絡,可以做為我們後面工作的一個總的提綱: 第一步、建立交叉編譯環境 沒有交叉開發經驗的讀者,可能一時很難接受這個概念。首先,要明白兩個概念:一般我們工作的機器,稱為開發機、主機;我們制作好的系統將要放到某台機器,如手機或另一台PC機,這台機我們稱為目標主機。 我們一般開發機上已經有一套開發工具,我們稱之為原生開發套件,我們一般就是用它們來寫程序,那麼,那什麼又是交叉編譯環境呢?其實一點也不神秘,也就是在開發機上再安裝一套開發工具,這套開發工具編譯出來的程序,如內核、系統工作或者我們自己的程序,是放在目標主機上運行的。 那麼或許有初學者會問,直接用原生開發工具為目標主機編譯程序不就完了?至少我當初是這麼想的。一般來說,我們的開發機都是X86平台,原生開發套件開發的工具,也針對X86平台,而我們的目標主機可能是PowerPC、IXP、MIPS……所以,我們的交叉編譯環境是針對某一類具體平台的。 一般來講,交叉開發環境需要二進制工具程序、編譯器、C鏈接庫,嵌入式開發常用的這三類軟件是: Binutils Gcc uClibc 當然,GNU包含的工具套件不僅於此,你還要以根據實際需要,進行選擇
第二步、編譯內核 開發工具是針對某一類硬件平台,內核同樣也是。這一步,我們需要用第一步中建立的工具,對內核進行編譯,對於有內核編譯經驗的人來說,這是非常簡單的;
第三步、建立根文件系統 也就是建立我們平常看到的bin、dev、proc……這一大堆目錄,以及一些必備的文件;另外,我們還需要為我們的目標系統安裝一些常用的工具軟件,如ls、ifconfig……當然,一個辦法是找到這些工具的源代碼,用第一步建立的交叉編譯工具來編譯,但是這些軟件一是數量多,二是某些體積較大,不適合嵌入式系統,這一步,我們一般都是用busybox來完成的,包括系統引導軟件init; 最後,我們為系統還需要建立初始化的引導文件,如inittab……
第四步、啟動系統 在這一步,我們把建立好的目標、文件、程序、內核及模塊全部拷貝到目標機存儲器上,如硬盤。然後為系統安裝bootloader,對於嵌入式系統,有許多引導程序可供我們使用。不過它們許多都有硬件平台的限制。當然,如果你是工作在X86,可以直接用lilo來引導,事實上,本文就是采用的lilo。 做到這一步,將目標存儲設備掛上目標機,如果順利,就可以啟動系統了。 當然,針對某些特別的平台,不能像硬盤這樣拷貝了,需要讀卡器、燒錄……但是基本的方法是相通的!
第五步、優化和個性化系統 通過前四步,我們已經得到了一個可以正常工作的系統。在這一步裡,就是發揮你想像的時候了……
本文的工作環境 項目根目錄/home/kendo/project ------>;我將它指定至PATH:$PRJROOT 子目錄及說明 目錄 內容 bootloader 目標板的引導加載程序,如lilo等 build-tools 建立交叉編譯平台的工具源碼 debug 調試工具及所有相關包 doc 項目中用到的所有文檔 images 編譯好的內核映像,以及根文件系統 kernel 各個版本的Linux內核源碼 rootfs 制作好的根文件系統 sysapps 目標板將要用到的系統應用系統,比如thttpd,udhcpd等 tmp 存放臨時文件 tools 編譯好的跨平台開發工具鏈以及C鏈接庫
工作的腳本 #!/usr/bin
export PROJECT=skynet export PRJROOT=/home/${PROJECT} export TARGET=i386-linux export PREFIX=${PRJROOT}/tools export TARGET_PREFIX=${PREFIX}/${TARGET} export PATH=${PREFIX}/bin:/bin:/sbin:/usr/bin:/usr/sbin
cd $PRJROOT
第二章 建立交叉編譯環境 在CU中發表的另一篇同名的貼子裡,我講述了一個全手工創建交叉編譯環境的方法。目前,創建交叉編譯環境,包括建立根文件,一般來講,有兩種方法: 手功創建 可以得到最大程序的個性化定制,缺點是過程繁雜,特別是極易出錯,注意這個“極”字,包括有經驗的開發人員; 自動創建 無它,方便而。
因為前一篇文章中,已經講述了全手工創建交叉編譯環境的一般性方法,本文就不打算再重復這個步驟了,感興趣的朋友,可以再去搜索那篇貼子,提醒一點的就是,在准備工具鏈的時候,要注意各個工具版本之間的搭配、每個工具需要哪些補丁,我建議你在google上針對這兩項搜索一下,准備一個清單,否則…… 本章要講述的是自動創建交叉編譯環境的方法。目標,針對商業硬件平台,廠家都會為你提供一個開發包,我用過XX廠家的IXP425和MIPS的,非常地方便,記得我第一次接觸嵌入式開發,拿著這個開發包自動化創建交叉編譯環境、編譯內核、建立根文件系統、創建Ram Disk,我反復做了三四次,結果還不知道自己究竟做了些什麼,呵呵,夠傻吧…… 所以,建議沒有這方面經驗的讀者,還是首先嘗試一下手工創建的方法吧,而本章接下來的內容,是送給曾經被它深深傷害而不想再次去親歷這項工作而又想提高交率而又在通用平台上工作沒有商業開發包的朋友。
建立交叉開發工具鏈 准備工具: buildroot-0.9.27.tar.tar 只需要一個軟件?對,其它的不用准備了,buildroot事實上是一個腳本與補丁的集合,其它需要用到的軟件,如gcc、uClibc,你只需在buildroot中指明相應的版本,它會自動去給你下載。 事實上,buildroot到網上去下載所需的所有工作是需要時間的,除非你的帶寬足夠,否則下載軟件時間或許會占去80%,而我在做這項工作之間,所需的工作鏈全部都在我本地硬盤上,我解壓開buildroot後,新建dl文件夾,將所有工具源碼的壓縮包拷貝進去,呵呵,buildroot就不用去網上下載了。
我的軟件清單: Linux-libc-headers-2.4.27.tar.bz2 Gcc-3.3.4.tar.bz2 binutils 2.15.91.0.2.tar.bz2 uClibc 0.9.27.tar.bz2 genext2fs_1.3.orig.tar.gz ccache-2.3.tar.gz
將它拷貝到${PRJROOT}/build-tools下,解壓 [root@skynet build-tools]# tar jxvf buildroot-0.9.27.tar.tar [root@skynet build-tools]#cd buildroot 配置它: [root@skynet build-tools]#make menuconfig Target Architecture (i386) --->; 選擇硬件平台,我的是i386 Build options --->; 編譯選項 這個選項下重要的是(${PRJROOT}/tools) Toolchain and header file location?編譯好的工具鏈放在哪兒? 如果你像我一樣,所有工具包都在本地,不需它到網上自動下載,可以把wget command選項清空; Toolchain Options --->; 工具鏈選項 --- Kernel Header Options 頭文件它會自動去下載,不過應該保證與你將要用的內核是同一個版本; [] Use the daily snapshot of uClibc? 使用最近的uClibc的snapshot Binutils Version (binutils 2.15.91.0.2) --->; Binutils的版本 GCC compiler Version (gcc 3.4.2) --->; gcc 版本
Build/install c++ compiler and libstdc++? [ ] Build/install java compiler and libgcj? 支持的語言,我沒有選擇java [ ] Enable ccache support? 啟用ccache的支持,它用於編譯時頭文件的緩存處理,用它來編譯程序,第一次會有點慢,但是以後的速度可就很理想了,呵呵…… --- Gdb Options 根據你的需要,選擇gdb的支持
Package Selection for the target --->; 這一項我沒有選擇任意一項,因為我打算根文件系統及busybox 等工具鏈創建成工,手工來做。 Target Options --->; 文件系統類型,根據實際需要選,我用的ext2;
配置完成後,編譯它: [root@skynet build-tools]#make
這一項工作是非常花時間的,我的工具包全部在本地,也花去我一小時十三分的時間,如果全要下載,我估計網速正常也要多花一兩個鐘頭。
經過漫長的等待(事實上並不漫長,去打了幾把游戲,很快過去了): …… make[1]: Leaving directory `/home/skynet/build-tools/buildroot/build_i386/genext2fs-1.3' touch -c /home/skynet/build-tools/buildroot/build_i386/genext2fs-1.3/genext2fs #-@find /home/skynet/build-tools/buildroot/build_i386/root/lib -type f -name \*.so\* | xargs /home/skynet/tools/bin/i386-linux-uclibc-strip --remove-section=.comment --remove-section=.note --strip-unneeded 2>;/dev/null || true; /home/skynet/build-tools/buildroot/build_i386/genext2fs-1.3/genext2fs -i 503 -b 1056 \ -d /home/skynet/build-tools/buildroot/build_i386/root -q -D target/default/device_table.txt /home/skynet/build-tools/buildroot/root_fs_i386.ext2
大功告成!!!
清點戰利品 讓我來看看它究竟做了哪些事情吧: [root@skynet skynet]# cd tools [root@skynet tools]# ls bin bin-ccache i386-linux i386-linux-uclibc include info lib libexec man usr
bin:所有的編譯工具,如gcc,都在這兒了,只是加了些指定的前綴; bin-ccache:如果在Toolchain optaion中沒有選擇對ccache的支持,就沒有這一項了; i386-linux:鏈接文件;實際指向include i386-linux-uclibc:uclibc的相關工具; include:供交叉開發工具使用的頭文件; info:gcc 的info文件; lib:供交叉開發工具使用的鏈接庫文件; ……
現在可以把編譯工具所在目錄XXX/bin添加至PATH了
測試工具鏈 如果你現在寫一個程序,用i386-linux-gcc來編譯,運行的程序會告訴你: ./test: linked against GNU libc 因為程序運行庫會尋到默認的/lib:/usr/lib上面去,而我們目前的uclibc的庫並不在那裡(雖然對於目標機來講,這是沒有錯的),所以,也只能暫時靜態編譯,試試它能否工作了。當然,你也可以在建好根文件系統後,試試用chroot……
第三章 編譯內核 本章的工作,是為目標機建立一個合適的內核,對於建立內核,我想有兩點值得考慮的: 1、功能上的選擇,應該能夠滿足需要的情況下,盡量地小; 2、小不是最終目的,穩定才是;
所以,最好編譯內核前有一份目標機硬件平台清單以及所需功能清單,這樣,才能更合理地裁減內核。
准備工具 Linux內核源碼,我選用的是Linux-2.4.27.tar.bz2
編譯內核 將Linux-2.4.27.tar.bz2拷貝至${PRJROOT}/kernel,解壓 #cd linux-2.4.27 //配置 # make ARCH=i386 CROSS_COMPILE=i386-linux- menuconfig //建立源碼的依存關系 # make ARCH=i386 CROSS_COMPILE=i386-linux- clean dep //建立內核映像 # make ARCH=i386 CROSS_COMPILE=i386-linux- bzImage ARCH指明了硬件平台,CROSS_COMPILE指明了這是交叉編譯,且編譯器的名稱為i386-linux-XXX,這裡沒有為編譯器指明路徑,是因為我前面已將其加入至環境變量PATH。
又是一個漫長的等待…… OK,編譯完成,673K,稍微大了點,要移到其它平台,或許得想辦法做到512以下才好,回頭來想辦法做這個工作。
安裝內核 內核編譯好後,將內核及配置文件拷貝至${PRJROOT}/images下。 # cp arch/i386/boot/bzImage ${PRJROOT}/images/bzImage-2.4.27-rmk5 # cp vmlinux ${PRJROOT}/images/vmlinux-2.4.27-rmk5 # cp System.map ${PRJROOT}/images/System-2.4.27-rmk5 # cp .config ${PRJROOT}/images/2.4.27-rmk5
我采用了後綴名的方式重命名,以便管理多個不同版本的內核,當然,你也可以不用這樣,單獨為每個版本的內核在images下新建對應文件夾也是可行的。
安裝內核模塊 完整內核的編譯後,剩下的工作就是建立及安裝模塊了,因為我的內核並沒有選擇模塊的支持(這樣擴展性差了一點,但是對於我的系統來說,功能基本上定死了,這樣影響也不太大),所以,剩下的步驟也省去了,如果你還需要模塊的支持,應該: //建立模塊 #make ARCH=i386 CROSS_COMPILE=i386-linux- modules //安裝內核模塊至${PRJROOT}/images #make ARCH=i386 CROSS_COMPILE= i386-linux- \ >;INSTALL_MOD_PATH=${PRJROOT}/images/modules-2.4.18-rmk5 \ >;modules_install
最後一步是為模塊建立依存關系,不能使用原生的depmod來建立,而需要使用交叉編譯工具。需要用到busybox中的depmod.pl腳本,很可惜,我在busybox1.0.0中,並沒有找到這個腳本,所以,還是借用了busybox0.63中scripts中的depmod.pl。 將depmod.pl拷貝至${PREFIX}/bin目錄中,也就是交叉編譯工具鏈的bin目錄。 #depmod.pl \ >;-k ./vmlinux –F ./System.map \ >;-b ${PRJROOT}/images/modules-2.4.27-rmk5/lib/modules >; \ >;${PRJROOT}/images/modules-2.4.27-rmk5/lib/modules/2.4.27-rmk5/modules.dep
注:後面討論移植內核和模塊內容時,我只會提到內核的拷貝,因為我的系統並沒有模塊的支持。如果你需要使用模塊,只需按相同方法將其拷貝至相應目錄即可。
附,內核編譯清單 附,內核選擇: 內核編譯記錄: Code maturity level options 不選 Loadable module support 不選 Processor type and features 根據實際,選擇處理器類型 General setup --->;
Networking support
PCI support (Any) PCI access mode
PCI device name database
System V IPC
Sysctl support (ELF) Kernel core (/proc/kcore) format
Kernel support for ELF binaries
Power Management support
Memory Technology Devices (MTD) --->; MTD設備,我用CF卡,不選
Parallel port support --->; 不選 Plug and Play configuration --->; 我的系統用不著即插即用,不選
Block devices --->;
Loopback device support
RAM disk support (4096) Default RAM disk size (NEW)
Initial RAM disk (initrd) support
Multi-device support (RAID and LVM) --->; 不選
Networking options --->; 基本上都選了
ATA/IDE/MFM/RLL support --->; 用了默認的
Telephony Support --->; 不選
SCSI support --->; 不選
Fusion MPT device support --->; 不選
I2O device support --->; 不選
Network device support --->; 根據實際情況選擇
Amateur Radio support --->; 不選
IrDA (infrared) support --->; 不選
ISDN subsystem --->; 不選
Old CD-ROM drivers (not SCSI, not IDE) --->; 不選
Input core support --->; 不選
Character devices --->;
Virtual terminal
Support for console on virtual terminal
Standard/generic (8250/16550 and compatible UARTs) serial support
Support for console on serial port
Multimedia devices --->; 不選
File systems --->;
Kernel automounter version 4 support (also supports v3)
Virtual memory file system support (former shm fs)
/proc file system support
Second extended fs support
Console drivers --->;
VGA text console 調試時接顯示器用
剩下三個都不要 Sound --->; USB support --->; Kernel hacking --->;
第四章 建立根文件系統 1、建立目錄 構建工作空間時,rootfs文件夾用來存放根文件系統, #cd rootfs 根據根文件系統的基本結構,建立各個對應的目錄: # mkdir bin dev etc lib proc sbin tmp usr var root home # chmod 1777 tmp # mkdir usr/bin usr/lib usr/sbin # ls dev etc lib proc sbin tmp usr var # mkdir var/lib var/lock var/log var/run var/tmp # chmod 1777 var/tmp
對於單用戶系統來說,root和home並不是必須的。 准備好根文件系統的骨架後,把前面建立的文件安裝到對應的目錄中去。 2、拷貝鏈接庫 把uclibc的庫文件拷貝到剛才建立的lib文件夾中: # cd ${PREFIX}/lib [root@skynet lib]# cp *-*.so ${PRJROOT}/rootfs/lib [root@skynet lib]# cp -d *.so.[*0-9] ${PRJROOT}/rootfs/lib
3、 拷貝內核映像和內核模塊 因為沒有模塊,所以拷貝模塊就省了, 新建boot目錄,把剛才建立好的內核拷貝過來 # cd /home/kendo/control-project/daq-module/rootfs/ # mkdir boot # cd ${PRJROOT}/images # cp bzImages-2.4.18-rmk5 /home/kendo/control-project/daq-module/rootfs/boot
4、 建立/dev下邊的設備文件 在linux中,所有的的設備文件都存放在/dev中,使用mknod命令創建基本的設備文件。 mknod命令需要root權限,不過偶本身就是用的root用戶,本來是新建了一個用戶專門用於嵌入式制作的,不過後來忘記用了…… # mknod -m 600 mem c 1 1 # mknod -m 666 null c 1 3 # mknod -m 666 zero c 1 5 # mknod -m 644 random c 1 8 # mknod -m 600 tty0 c 4 0 # mknod -m 600 tty1 c 4 1 # mknod -m 600 ttyS0 c 4 64 # mknod -m 666 tty c 5 0 # mknod -m 600 console c 5 1 基本的設備文件建立好後,再創建必要的符號鏈接: # ln -s /proc/self/fd fd # ln -s fd/0 stdin # ln -s fd/1 stdout # ln -s fd/2 stderr # ls console fd mem null random stderr stdin stdout tty tty0 tty1 ttyS0 zero
設備文件也可以不用手動創建,聽說RedHat /dev下的腳本MAKEDEV 可以實現這一功能,不過沒有試過……
基本上差不多了,不過打算用硬盤/CF卡來做存儲設備,還需要為它們建立相關文件,因為我的CF在目標機器上是CF-to-IDE,可以把它們等同來對待,先看看Redhat 下邊had的相關屬性: # ls -l /dev/hda brw-rw---- 1 root disk 3, 0 Jan 30 2003 /dev/hda # ls -l /dev/hda1 brw-rw---- 1 root disk 3, 1 Jan 30 2003 /dev/hda1 對比一下,可以看出,had類型是b,即塊設備,主編號為3,次編號從0遞增,根限位是 rw-rw----,即660,所以: # mknod -m 660 hda b 3 0 # mknod -m 660 hda1 b 3 1 # mknod -m 660 hda2 b 3 2 # mknod -m 660 hda3 b 3 3
5、添加基本的應用程序 未來系統的應用程序,基本上可以分為三類: 基本系統工具,如ls、ifconfig這些…… 一些服務程序,管理工具,如WEB、Telnet…… 自己開發的應用程序
這裡先添加基本的系統工具,有想過把這些工具的代碼下載下來交叉編譯,不過實在是麻煩,用BusyBox,又精簡又好用…… 將busybox-1.00.tar.gz下載至sysapps目錄下,解壓: #tar zxvf busybox-1.00.tar.gz #cd busybox-1.00 //進入配置菜單 #make TARGET_ARCH=i386 CROSS=i386-linux- PREFIX=${PRJROOT}/rootfs menuconfig //建立依存關系 #make TARGET_ARCH=i386 CROSS= i386-linux- PREFIX=${PRJROOT}/rootfs dep //編譯 #make TARGET_ARCH=i386 CROSS= i386-linux- PREFIX=${PRJROOT}/rootfs //安裝 #make TARGET_ARCH=i386 CROSS= i386-linux- PREFIX=${PRJROOT}/rootfs install
# cd ${PRJROOT}/rootfs/bin # ls addgroup busybox chown delgroup echo kill ls mv ping rm sleep adduser chgrp cp deluser grep ln mkdir netstat ps rmdir umount ash chmod date dmesg hostname login mount pidof pwd sh vi 一下子多了這麼多命令…… 配置busybox的說明: A、如果編譯時選擇了: Runtime SUID/SGID configuration via /etc/busybox.conf 系統每次運行命令時,都會出現“Using fallback suid method ” 可以將它去掉,不過我還是在/etc為其建了一個文件busybox.conf搞定; B、 Do you want to build BusyBox with a Cross Compiler? (i386-linux-gcc) Cross Compiler prefix 這個指明交叉編譯器名稱(其實在編譯時的命令行已指定過了……) C、安裝選項下的(${PRJROOT}/rootfs) BusyBox installation prefix,這個指明了編譯好後的工具的安裝目錄。 D、靜態編譯好還是動態編譯好?即是否選擇 [ ] Build BusyBox as a static binary (no shared libs) 動態編譯的最大好處是節省了寶貴空間,一般來說都是用動態編譯,不過我以前動態編譯出過問題(其實是庫的問題,不關busybox的事),出於慣性,我選擇了靜態編譯,為此多付出了107KB的空間。 E、其它命令,根據需要,自行權衡。
6、系統初始化文件 內核啟動時,最後一個初始化動作就是啟動init程序,當然,大多數發行套件的Linux都使用了與System V init相仿的init,可以在網上下載System V init套件,下載下來交叉編譯。另外,我也找到一篇寫得非常不錯的講解如何編寫初始化文件的文件,bsd-init,回頭附在後面。不過,對於嵌入式系統來講,BusyBox init可能更為合適,在第6步中選擇命令的時候,應該把init編譯進去。 #cd ${PRJROOT}/rootfs/etc #vi inittab 我的inittal文件如下: #指定初始化文件 ::sysinit:/etc/init.d/rcS #打開一個串口,波特率為9600 ::respawn:/sbin/getty 9600 ttyS0 #啟動時執行的shell ::respawn:/bin/sh #重啟時動作 ::restart:/sbin/init #關機時動作,卸載所有文件系統 ::shutdown:/bin/umount -a –r
保存退出;
再來編寫rcS腳本: #mkdir ${PRJROOT}/rootfs/etc/init.d #cd ${PRJROOT}/rootfs/etc/init.d #vi rcS 我的腳本如下: #!/bin/sh
#Set Path PATH=/sbin:/bin export PATH
syslogd -m 60 klogd
#install /proc mount -n -t proc none /proc
#reinstall root file system by read/write mode(need: /etc/fstab) mount -n -o remount,rw /
#reinstall /proc mount -n -o remount,rw -t proc none /proc
#set lo ip address ifconfig lo 127.0.0.1
#set eth0 ip address #當然,這樣子做只是權宜之計,最後做的應該是在這一步引導網絡啟動腳本,像RedHat #那樣,自動讀取所有指定的配置文件來啟動 ifconfig eth0 192.168.0.68 netmask 255.255.255.0
#set route #同樣的,最終這裡應該是運行啟動路由的腳本,讀取路由配置文件 route add default gw 192.168.0.1
#還差一個運行服務程序的腳本,哪位有現成的麼? #網卡/路由/服務這三步,事實上可以合在一步,在rcS這一步中,做一個循環,運行指定啟動目錄下的所有腳,先將就著這麼做吧,確保系統能夠正常啟動了,再來寫這個腳本。
#set hostname hostname MyLinux
保存退出。
編寫fstab文件 #vi fstab 我的fstab很簡單: /dev/hda1 / ext2 defaults 1 1 none /proc proc defaults 0 0
第五章 讓MyLinux能夠啟動 前一章,我們把編譯好的內核、應用程序、配置文件都拷貝至rootfs目錄對應的子目錄中去了,這一步,就是把這些文件移植至目標機的存儲器。這裡,我是先另外拿一塊硬盤,掛在我的開發機上做的測試,因為我的本本用來寫文檔,PC機用來做開發機,已經沒有另外的機器了……但是本章只是講述一個一般性的過程,並不影響你直接在目標主機上的工作。 因為以後目標機識別硬盤序號都是hda,而我現在直接掛上去,則會是hdb、hdc……這樣,安裝lilo時有點麻煩(雖然也可以實現)。所以我想了另一個辦法: 把新硬盤掛在IDE0的primary上,進入linux後,會被認為是had; 原來主機的裝Redhat的硬盤,我將它從IDE0的primary上變到了IDE1 的primary,因為它的lilo早已裝好,基本上不影響系統的使用;
分區和格式化 BIOS中改為從第二個硬盤啟動;也就是從我原來開發機啟動,新的硬盤被識別成了had。 #fdisk /dev/hda 用d參數刪除已存在的所有分區 用n參數新建一個分區,也是就/dev/hda1 格式化 #mkfs.ext2 /dev/hda1
安裝bootloader 因為我是X86平台,所以直接用了lilo,如果你是其這平台,當然,有許多優秀的bootloader供你選擇,你只需查看其相應的說明就可以了。 編譯lilo配置文件,我的配置文件名為target.lilo.conf,置於${PRJROOT}/rootfs/etc目錄。內容如下所示: boot=/dev/hda disk=/dev/hda bios=0x80 image=/boot/bzImage-2.4.18-rmk5 label=Linux root=/dev/hda1 append="root=/dev/hda1" read-only
//新建文件夾,為mount做新准備 #mkdir /mnt/cf //把目標硬盤mount上來 #mount –t ext2 /dev/hdc1 /mnt/cf 回到rootfs #cd ${PRJROOT}/rootfs 拷貝所有文件至目標硬盤 #cp –r * /mnt/cf
這樣,我們所有的文件都被安裝至目標硬盤了,當然,它還不能引導,因為沒有bootloader。使用如下命令: # lilo -r /mnt/cf -C etc/target.lilo.conf Warning: LBA32 addressing assumed Added Linux * -r :改變根目標為/mnt/cf ,這樣配置文件其實就是/mnt/cf/etc/target.lilo.conf,也就是我們先前建立的文件。 當然,完成這一步,需要lilo22.3及以後版本,如果你的版本太舊,比如Redhat9.0自帶的,就會出現下面的信息: #lilo –r /mnt/cf –C etc/target.lilo.conf Fatal: open /boot/boot.b: No such file or directory 這時,你需要升級你的lilo,或者重新安裝一個。
啟動系統 #umount /mnt/cf #reboot
將BIOS改為從IDE0啟動,也就是目標硬盤。如果一切順利,你將順利進入一個屬於你的系統。
回頭再來看看我們的工作空間吧 [root@skynet lib]# df /dev/hda1 Filesystem 1K-blocks Used Available Use% Mounted on /dev/hda1 3953036 1628 3750600 1% /mnt/cf
總共花去了我1628KB的空間,看來是沒有辦法放到軟盤裡邊去了^o^,不過一味求小,並不是我的目標。
[root@skynet skynet]# ls ${PRJROOT} bootloader build-tools debug doc images kernel rootfs sysapps tmp tools 這幾個目錄中的文件,呵呵,與本文一開頭規劃的一樣
[root@skynet skynet]# ls build-tools/ buildroot buildroot-0.9.27.tar.tar 包含了buildroot源碼及壓縮包,事實上buildroot下邊還包括了GNU其它工具的源碼、編譯文件等諸多內容,是我們最重要的一個文件夾,不過到現在它已經沒有多大用處了,如果你喜歡,可以將它刪除掉(不建議)。
[root@skynet skynet]# ls images 2.4.18-rmk5 bzImage-2.4.18-rmk5 System-2.4.18-rmk5 vmlinux-2.4.18-rmk5 內核映像及配置文件等,如果你有模塊,因為還有相應的目錄
[root@skynet skynet]# ls kernel/ linux-2.4.27 linux-2.4.27.tar.bz2 內核源碼及壓縮包
[root@skynet skynet]# ls rootfs/ bin boot dev etc home lib linuxrc proc root sbin tmp usr var 制作好的根文件系統,重中之重,注意備份……
[root@skynet skynet]# ls sysapps/ busybox-1.00 busybox-1.00.tar.gz busybox-1.00源碼包,或許你還要繼續添加/刪除一些命令……
[root@skynet skynet]# ls tools bin i386-linux i386-linux-uclibc include info lib man 這個也很重要,我們制作好的交叉開發工具鏈。如果你要繼續開發程序,這個目錄重要性就很高了。
其它目錄暫時是空的。
第六章 完善MyLinux 關於進一步的調試,你可以在開發機上使用chroot /mnt/cf /bin/sh這樣的命令,以使我們在目標根文件系統上工作。
支持多用戶 因為我在編譯busybox時,已經將它的多用戶那一大堆命令編譯了進來。現在關鍵是的要為其建立相應的文件; 進入原來的開發機,進入rootfs目錄,切換根目錄 #chroot rootfs/ /bin/sh A、 建立/etc/passwd文件,我的文件內容如下: root:x:0:0:root:/root:/bin/bash B、 建立/etc/group文件,我的文件內容如下: root:x:0: bin:x:1: sys:x:2: kmem:x:3: tty:x:4: tape:x:5: daemon:x:6: disk:x:7: C、 為root建立密碼 #passwd root
試試用addgroup/addusr……這堆命令。然後重啟,從目標硬盤上啟動;從console口,9600登陸試試(因為我在inittab中啟用了ttyS0,我未來的目標機,是沒有顯卡的,需要從console口或SSH進去管理) MyLinux login: root Password:
BusyBox v1.00 (2004.10.10-04:43+0000) Built-in shell (ash) Enter 'help' for a list of built-in commands.
~ # 成功了……
增加WEB Server Busybox裡邊有httpd選項,不過我編譯時並沒有選擇,所以還是自己來安裝。我使用的軟件是thttpd-2.25b.tar.gz,將它移至sysapps目錄下。 [root@skynet sysapps]# tar zxvf thttpd-2.25b.tar.gz [root@skynet sysapps]# cd thttpd-2.25b //配置 [root@skynet thttpd-2.25b]# CC=i386-linux-gcc ./configure --host=$TARGET …… i386-linux-gcc -static htpasswd.o -o htpasswd -lcrypt make[1]: warning: Clock skew detected. Your build may be incomplete. make[1]: Leaving directory `/home/skynet/sysapps/thttpd-2.25b/extras' //拷貝至根文件目錄 [root@skynet thttpd-2.25b]# cp thttpd ${PRJROOT}/rootfs/usr/sbin //trip處理 [root@skynet thttpd-2.25b]# i386-linux-strip ${PRJROOT}/rootfs/usr/sbin/thttpd
剩下的,就發揮各人的想像吧……
PDF版本及後續PDF更新版本,你可以在 http://www.skynet.org.cn/viewthread.php?tid=82 下載。 不過好像下載要先注冊(我沒找到如何取消這一限制)!