摘要:本文主要是對(duì)基于嵌入式Linux在S3C2410開(kāi)發(fā)板上的移值過(guò)程所需要的三個(gè)重要文件:BootLoader引導(dǎo)程序uboot、Linux內(nèi)核的映像文件zImage、根文件系統(tǒng)rootfs的制作過(guò)程,以及怎樣將這三個(gè)文件移植到自己開(kāi)發(fā)板上所涉及到的一些關(guān)鍵環(huán)節(jié)作了詳細(xì)的介紹說(shuō)明。
關(guān)鍵詞:BootLoader引導(dǎo);內(nèi)核的映像;根文件系統(tǒng);下載;燒寫(xiě)
中圖分類號(hào):TP311文獻(xiàn)標(biāo)識(shí)碼:A文章編號(hào):1009-3044(2008)33-1513-04
The Key Transplant Processes of Embedded Linux System
HE Zhi-hong1,2, HE Wei-min1
(1. East China University of Technology, Fuzhou 344000, China; 2. Sontian Institute of Guangzhou University, Guangzhou 510515, China)
Abstract: This paper mainly refers to three primary files when transplanting a based-Linux embedded system: uboot, zImage and rootfs, how to be done and transplant to our developed board in detail. And it also come to some key steps what our developed board refers to.
Key words: BootLoader guidance; the core image; root file system; downloads; programming
1 引言
嵌入式Linux系統(tǒng)移植的工作能否正常進(jìn)行以及移植后系統(tǒng)能否正常運(yùn)行,與移植過(guò)程的幾個(gè)小環(huán)節(jié)是分不開(kāi)的。其實(shí)我們用于做嵌入式開(kāi)發(fā)的ARM開(kāi)發(fā)板,它們也是一臺(tái)簡(jiǎn)單的電腦來(lái)的,也具備計(jì)算機(jī)系統(tǒng)的絕大部分接口。但是,嵌入式開(kāi)發(fā)板上一般都沒(méi)有提供類似個(gè)人電腦(PC機(jī))在主板上的BIOS程序段,那么我們又怎樣能使它們的部件運(yùn)轉(zhuǎn)起來(lái)呢?這只能靠我們用戶自己去做一個(gè)類似BIOS的硬件啟動(dòng)程序,該程序我們稱作BootLoader程序;另外就是即便是我們啟動(dòng)了硬件,如何讓我們的開(kāi)發(fā)板能夠更好地發(fā)揮它的功能呢,那就是需要一個(gè)類似操作系統(tǒng)的大管家,而嵌入式系統(tǒng)一般來(lái)說(shuō),在硬件上是比較簡(jiǎn)單的(考慮到成本),所以,它不會(huì)象個(gè)人電腦那樣有硬盤(pán)、光驅(qū)、軟驅(qū)等之類的東西,甚至內(nèi)存都是比較小的,因此,我們?cè)诙ㄖ魄度胧讲僮飨到y(tǒng)的時(shí)候,一般以“夠用”為原則,不需要浪費(fèi)太多的存儲(chǔ)空間而節(jié)省生產(chǎn)成本,因此就需要對(duì)Linux操作系統(tǒng)的內(nèi)核進(jìn)行壓縮映像,這就是我們說(shuō)的Linux內(nèi)核的映像文件。那么在Linux嵌入式系統(tǒng)的移植過(guò)程中涉及到三個(gè)文件,這三個(gè)文件分為:處于最底層的BootLoader引導(dǎo)程序、Linux內(nèi)核的映像文件、另外就支持用戶操作使用的根文件系統(tǒng)。所以,本文從這三個(gè)文件的制作過(guò)程中談?wù)撐覀円⒁獾年P(guān)鍵環(huán)節(jié)。
2 BootLoader引導(dǎo)程序uboot制作的關(guān)鍵環(huán)節(jié)
bootloader的兩大功能:一是下載功能,既通過(guò)網(wǎng)口、串口或者USB口下載文件到RAM中;一是對(duì)flash芯片的讀寫(xiě)功能。具體來(lái)說(shuō):當(dāng)用戶輸入啟動(dòng)Linux的命令的時(shí)候,u-boot會(huì)將 kernel 映像(zImage)和從 nand flash 上讀到 RAM 空間中,為內(nèi)核設(shè)置啟動(dòng)參數(shù),調(diào)用內(nèi)核,從而啟動(dòng)Linux。
Uboot是嚴(yán)重依依賴于硬件的體系結(jié)構(gòu)的,而我們從網(wǎng)上下載的u-boot源代碼只是提供了一種框架結(jié)構(gòu),如果要制作適合我們自己的開(kāi)發(fā)板的引導(dǎo)程序uboot,必需在它的基礎(chǔ)上進(jìn)行修改。下面介紹uboot制作過(guò)程中的關(guān)鍵步驟:
1) 建立適合自己開(kāi)發(fā)板的board平臺(tái)目錄
可以參照board/smdk2410目錄,在源碼的board下建立自己的平臺(tái)目錄比如:gxy(這是開(kāi)發(fā)板的名稱起名叫g(shù)xy,可以依自己的喜好隨意起),并將board/smdk2410目錄中的所有文件拷貝到gxy目錄下,將smdk2410.c更名為gxy.c。
2) 用vi修改u-boot頂層目錄下的Makefile文件
在u-boot頂層目錄下的Makefile文件中找到:
smdk2410_config : unconfig
@./mkconfig $(@:_config=) arm arm920t smdk2410 NULL s3c24x0
在其后面添加:
gxy _config : unconfig
@./mkconfig $(@:_config=) arm arm920t gxy NULL s3c24x0
各項(xiàng)的意思為:arm: CPU的架構(gòu)(ARCH);arm920t:CPU的類型(CPU),其對(duì)應(yīng)于cpu/arm920t子目錄;gxy:開(kāi)發(fā)板的型號(hào)(BOARD),對(duì)應(yīng)于board/gec2410目錄;NULL: 開(kāi)發(fā)者/或經(jīng)銷商(vender);s3c24x0:片上系統(tǒng)(SOC)。
3) 修改board/gxy/Makefile文件
將 OBJS := smdk2410.o flash.o 改為 OBJS := gxy.o flash.o
4) 以include/configs/smdk2410.h文件為藍(lán)本復(fù)制一個(gè)include/configs/gxy.h文件。
Cp include/configs/smdk2410.h include/configs/gxy.h
5) 修改cpu/arm920t/config.mk文件。
將 PLATFORM_CPPFLAGS +=$(call cc-option,-mapcs-32,-mabi=apcs-gnu)
改為 PLATFORM_CPPFLAGS +=$(call cc-option,-mapcs-32,$(call cc-option,-mabi=apcs-gnu))
6) 在uboot頂層目錄中設(shè)置交叉編譯環(huán)境變量后直行編譯,執(zhí)行下列語(yǔ)句:
export PATH=/usr/local/arm/2.95.3/bin:$PATH; make gxy_config; make all ARCH=arm
編譯過(guò)程如果不出現(xiàn)錯(cuò)誤,則可正常生成u-boot.bin了。
3 Linux內(nèi)核的映像文件zImage制作的關(guān)鍵環(huán)節(jié)
當(dāng)把Linux內(nèi)核文件下載后,制作Linux內(nèi)核的映像文件zImage需要經(jīng)過(guò)以下幾個(gè)環(huán)節(jié):(假設(shè)用的內(nèi)核版本為L(zhǎng)inux2.6.8.1,編譯器為ross-3.3.2)
3.1 修改Linux內(nèi)核頂層下的Makefile文件
修改內(nèi)核目錄樹(shù)根下的的Makefile,指明體系結(jié)構(gòu)是arm,交叉編譯工具是arm-Linux-。找到ARCH和CROSS_COMPILE,修改為:
ARCH ?= arm
CROSS_COMPILE ?= arm-Linux-
3.2 設(shè)置flash分區(qū)
在arch/arm目錄中建立一個(gè)mach-gxy的文件夾,并將arch/arm/mach-s3c2410目錄下的所有文件及文件夾復(fù)制到mach-gxy目錄下,并將相應(yīng)的文件名進(jìn)行修改。再修改下面三個(gè)文件的相關(guān)信息:
arch/arm/mach-gxy/devs.c; 指明分區(qū)信息
arch/arm/mach-gxy/mach-smdk2410.c; 指定啟動(dòng)時(shí)初始化
drivers/mtd/nand/gxy.c; 禁止Flash ECC校驗(yàn)
3.2.1 內(nèi)存分區(qū)信息

內(nèi)存分區(qū)信息如上圖,則修改結(jié)構(gòu)體partition_info[]為如下內(nèi)容:
static struct mtd_partition partition_info[] ={
{ /* 256kB */name: \"boot\", size: 0x00040000, offset: 0x0, },
{ /*1.75MB */ name: \"kernel\",size: 0x001C0000, offset: 0x00040000, },
{ /* 30MB */ name: \"root\", size: 0x01e00000,offset: 0x00200000, },
{ /* 32MB */ name: \"user\", size: 0x02000000, offset: 0x02000000,}
};
在結(jié)構(gòu)體nandset中添加Nand Flash分區(qū)信息:
struct s3c2410_nand_set nandset ={
nr_partitions: 4, /* 指明partition_info中定義的分區(qū)數(shù)目 */
partitions: partition_info, /* 分區(qū)信息表*/}};
在結(jié)構(gòu)體superlpplatform中提供Nand Flash芯片支持,
struct s3c2410_platform_nand superlpplatform={ tacls:0,
twrph0:30,
twrph1:0,
sets: nandset,
nr_sets: 1
};
在結(jié)構(gòu)體s3c_device_nand中添加Nand Flash芯片支持到Nand Flash驅(qū)動(dòng)對(duì)dev成員的賦值
struct platform_device s3c_device_nand = {
.name = \"gxy-nand\",/*設(shè)備名稱*/
.id = 1,/* id: 有效設(shè)備編號(hào),如果只有唯一的一個(gè)設(shè)備為1,有多個(gè)設(shè)備從0開(kāi)始計(jì)數(shù)/
.num_resources = ARRAY_SIZE(s3c_nand_resource),/* 有幾個(gè)寄存器區(qū)*/
.resource = s3c_nand_resource, /*寄存器區(qū)數(shù)組首地址*/
.dev = {.platform_data = superlpplatform}/*支持的Nand Flash設(shè)備*/
};
3.2.2 指定啟動(dòng)時(shí)依據(jù)我們對(duì)內(nèi)存的分區(qū)設(shè)置進(jìn)行初始化配置
修改arch/arm/mach-gxy/mach-smdk2410.c文件中的smdk2410_devices[].指明初始化時(shí)包括我們?cè)谇懊嫠O(shè)置的flash分區(qū)信息
static struct platform_device *smdk2410_devices[] __initdata = {s3c_device_usb,
s3c_device_lcd, s3c_device_wdt, s3c_device_i2c, s3c_device_iis, /* 添加后面的語(yǔ)句即可 */s3c_device_nand, };
3.2.3 禁止Flash ECC校驗(yàn)
我們的內(nèi)核都是通過(guò)UBOOT寫(xiě)到Nand Flash的, UBOOT通過(guò)的軟件ECC算法產(chǎn)生ECC校驗(yàn)碼, 這與內(nèi)核校驗(yàn)的ECC碼不一樣,內(nèi)核中的ECC碼是由gxy中Nand Flash控制器產(chǎn)生的。所以,我們?cè)谶@里選擇禁止內(nèi)核ECC校驗(yàn)。修改drivers/mtd/nand/gxy.c 文件中s3c2410_nand_init_chip()函數(shù),在該函數(shù)體最后加上一條下面的語(yǔ)句即可。
chip->eccmode = NAND_ECC_NONE
3.3 支持啟動(dòng)時(shí)掛載devfs
為了我們的內(nèi)核支持devfs以及在啟動(dòng)時(shí)并在/sbin/init運(yùn)行之前能自動(dòng)掛載/dev為devfs文件系統(tǒng),在fs/Kconfig文件中找到menu \"Pseudo filesystems\",添加如下語(yǔ)句:
config DEVFS_FS
bool \"/dev file system support (OBSOLETE)\"
default y
config DEVFS_MOUNT
bool \"Automatically mount at boot\"
default y
depends on DEVFS_FS
3.4 配置編譯內(nèi)核
復(fù)制arch/arm/configs/目錄下的smdk2410_defconfig為當(dāng)前目錄下的.config文件;
執(zhí)行 make smdk2410_defconfig;
再執(zhí)行 make menuconfig;
在 smdk2410_defconfig 基礎(chǔ)上,增加一些相應(yīng)的內(nèi)核配置選項(xiàng)如:
Loadable module support -->
[*] Enable loadable module suppor
[*] Automatic kernel module loading
System Type --> [*] S3C2410 DMA support
Boot options --> Default kernel command string:
noinitrd root=/dev/mtdblock2 init=/Linuxrc console=ttySAC0,115200
/*說(shuō)明:mtdblock2代表我的第3個(gè)flash分區(qū),它是rootfs console=ttySAC0,115200使kernel啟動(dòng)期間的信息全部輸出到串口0上.*/
Floating point emulation -->
[*] NWFPE math emulation/*說(shuō)明:這個(gè)是大多數(shù)二進(jìn)制運(yùn)行所必須有的選項(xiàng)*/
Device Drivers -->
Memory Technology Devices (MTD) -->
[*] MTD partitioning support /*支持MTD分區(qū),在前面設(shè)置的分區(qū)才有意義*/
[*] Command line partition table parsing/*支持從命令行設(shè)置flash分區(qū)信息*/
File systems -->
Pseudo filesystems -->
[*] /proc file system support,
[*] Automatically mount at boot (NEW)
[*] Virtual memory file system support (former shm fs)
[*] /dev file system support (OBSOLETE)
Miscellaneous filesystems -->
<*> Compressed ROM file system support (cramfs) /*支持cramfs*/
Network File Systems -->
<*> NFS file system support
保存退出,產(chǎn)生.config文件。再執(zhí)行make編譯完成后會(huì)在arch/arm/boot/目錄下生產(chǎn)zImage內(nèi)核映象,這就是我們要移植到開(kāi)發(fā)板上的內(nèi)核映象文件。
4 根文件系統(tǒng)rootfs制作的關(guān)鍵環(huán)節(jié)
4.1 建立工作目錄(根目錄)
設(shè)定根目錄為/root/build_rootfs/, 下載busybox到該目錄,該目錄就是我們要移植到目標(biāo)板上的目錄,對(duì)于嵌入式的文件系統(tǒng),根目錄下必要的目錄包括bin,dev,etc,usr,lib,sbin,并在各目錄中復(fù)制相應(yīng)的文件。
4.2 交叉編譯busybox
首先,添加交叉工具鏈:export PATH=/usr/local/arm/3.3.2/bin:$PATH;
其次,配置busybox,執(zhí)行:make defconfig,make menuconfig進(jìn)行相應(yīng)項(xiàng)的配置比如:
Busybox setting->builds options->[*] build busybox as a static binary;
Busybox setting->installitation options->[*] don’t use /usr等根據(jù)自己的需要進(jìn)行選項(xiàng)配置。
最后,編譯安裝,執(zhí)行:make ARCH=arm CROSS_COMPILE=arm-Linux- CONFIG_PREFIX=/root/build_rootfs/rootfs all install語(yǔ)句,
其中:ARCH指定平臺(tái),CROSS_COMPILE指定交叉編譯,CONFIG_PRRFIX指定安裝的路徑。
4.3 copy C庫(kù)
交叉應(yīng)用程序的開(kāi)發(fā)需要用到交叉編譯的鏈接庫(kù),交叉編譯的鏈接庫(kù)是在交叉工具鏈的lib目錄下;我們?cè)谝浦矐?yīng)用程序到我們的目標(biāo)板的時(shí)候,需要把交叉編譯的鏈接庫(kù)也一起移植到目標(biāo)板上,應(yīng)從/usr/local/arm/3.3.2/lib目錄來(lái)拷貝庫(kù),此目錄下有四種類型的文件。實(shí)際的共享鏈接庫(kù)如:libc-2.3.2.so;主修訂版本的符合鏈接如:libc.so.6;與版本無(wú)關(guān)的符合鏈接(鏈接到主修訂版本的符合鏈接)如:libc.so;靜態(tài)鏈接庫(kù)包文件如:libc.a。以上四種類型的文件,我們可以只需要兩種:實(shí)際的共享鏈接庫(kù);主修訂版本的符合鏈接,還有動(dòng)態(tài)連接器及其符號(hào)鏈接。拷貝交叉鏈接庫(kù),我們最好是寫(xiě)一個(gè).sh文件來(lái)完成,如在/usr/local/arm/3.3.2/lib目錄下編寫(xiě):cp.sh文件,內(nèi)容如下:
for file in libc libcrypt libdl libm libpthread libresolv libutil
do
cp $file-*.so /root/build_rootfs/rootfs/lib
cp -d $file.so.[*0-9] /root/build_rootfs/rootfs/lib
done
cp -d ld*.so* /root/build_rootfs/rootfs/lib
保存退出,執(zhí)行:source cp.sh命令,這樣就把鏈接庫(kù)復(fù)制過(guò)來(lái)了。當(dāng)然如果需要把剛復(fù)制過(guò)來(lái)的體積縮小,可執(zhí)行:arm-Linux-strip –s /root/build_rootfs/rootfs/lib/lib*語(yǔ)句來(lái)完成。
4.4 建立配置文件
內(nèi)核啟動(dòng)的最后,會(huì)執(zhí)行sbin/init程序,init程序在啟動(dòng)的最后會(huì)執(zhí)行/bin/sh,sh在啟動(dòng)的時(shí)候會(huì)讀取/etc/profile文件。可以在/etc/profile文件里設(shè)定PATH,LD_RARYLIB_PATH環(huán)境變量,目的是配置用戶程序運(yùn)行的環(huán)境,配置該文件內(nèi)容如下:
#!/bin/sh
echo \"Set seaech library in /etc/profile\"
export LD_LIBRARY_PATH=/lib
echo \"Set user path in /etc/profile\"
export PATH=/bin:/sbin:/usr/bin
保存退出
4.5 制作cramfs映像
制作cramfs映像,需要用到mkcramfs工具,把它復(fù)制到“/root/build_rootfs”目錄下。執(zhí)行:./mkcramfs rootfs rootfs.cramfs命令,rootfs.cramfs就是我們要燒寫(xiě)到目標(biāo)板的映像文件。
5 燒寫(xiě)到開(kāi)發(fā)板上
至此,三個(gè)文件算全部制作好,接下來(lái)就是把這三個(gè)文件燒寫(xiě)(下載)到開(kāi)發(fā)板上了。
首先,可以用DNW工具將uboot下載到開(kāi)發(fā)板上,先選擇0或者1,按”N”;再選擇2則可將uboot燒鍋寫(xiě)到開(kāi)發(fā)板上。
其次,用TFTP燒寫(xiě)內(nèi)核,可執(zhí)行下列語(yǔ)句完成:
tftp 0x30008000 zImage
nand erase 0x400000x1c0000
nand write 0x30008000 0x400000x1c0000
第三,燒寫(xiě)根文件,可執(zhí)行下列語(yǔ)句完成:
tftp ox30008000 rootfs.cramfs
nand erase 0x200000 0x1e00000
nand write 30008000 0x200000 0x1e00000
第四,設(shè)置自動(dòng)運(yùn)行:
SETENV BOOTCMD NAND READ 30008000 0x400000x1c0000
go 30008000
Saveenv
第五,重啟開(kāi)發(fā)板,則整個(gè)Linux在gxy開(kāi)發(fā)板上的移植工作完成。
6 結(jié)束語(yǔ)
本文對(duì)Linux在嵌入開(kāi)發(fā)板移植的實(shí)際制作過(guò)程中必不可缺少的重要環(huán)節(jié)作了詳細(xì)的介紹,使得讓從事嵌入式研究與開(kāi)發(fā)人員少走不必要的彎路。我堅(jiān)信,在不久的將來(lái),會(huì)有越來(lái)越多的人從事嵌入式的行業(yè)里來(lái),本篇對(duì)從事嵌入式Linux系統(tǒng)的移植有很好的啟發(fā)作用。
參考文獻(xiàn):
[1] Linux內(nèi)核源代碼包(版本2.6.8.1).
[2] DANIEL P.BOVET MARCO CESATI. UNDERSTANDING THE Linux KERNEL.
[3] 基于Linux嵌入式系統(tǒng)的研究與實(shí)現(xiàn)[J]. 計(jì)算機(jī)系統(tǒng)應(yīng)用,2004.
[4] 基于Linux的嵌入式系統(tǒng)的啟動(dòng)設(shè)計(jì)[J]. 電子科,2004.
[5] 孫瓊. 嵌入式Linux應(yīng)用程序開(kāi)發(fā)詳解[M]. 郵電出版社.