顯示具有 embedded 標籤的文章。 顯示所有文章
顯示具有 embedded 標籤的文章。 顯示所有文章

星期一, 5月 12, 2008

轉載 [新人培訓之2 ] 如何交叉編譯 應用程序,技巧,注意事項

轉載自: http://blog.chinaunix.net/u/22617/showart_372057.html
作者: bob_zhang2004@163.com
潤飾: Richman

最近大家都涉及 cross compile , 感覺大家的路子有點偏 ,覺得有必要糾正一下。

一般的應用程序,編譯的步驟無外乎 ./configure && make && make install

但是對於 cross compile 不能照搬,尤其要注意不能輕易 make install (當然如果指定了 --prefix就無所謂了,否則可能會覆蓋標準路徑的程式就慘了)
這裡有兩個思路:

1. 對於剛開始 cross compile 的人來說,往往很暈,總想借助 ./configure 後面加一堆參數來解決,比如
./configure --target=arm-9tdmi-linux-gnu --host=arm-9tdmi-linux-gnu

對於一般的小的程序來說,應該沒有問題,而且也推薦大家這樣用。
但是要注意 , 這樣作之前,先要
./configure --help | grep --host
看看有沒有這樣的選項,如果沒有呢?
想想也可能, 如果程序的作者根本沒有考慮到除了x86的平台呢?你只能自己改寫 Makefile 了。

所以 ./configure 不是萬能的,而且語法很混亂,不要指望 ./configure 幫你做好所有的事。而且侷限很大。

2. 所以這個時候 ,就要求 cross compile 的第二個層次,自己改寫 Makefile,想怎麼改就怎麼改,靈活性最大。
一開始先 ./configure , 跟平台有關的參數一律不加。

./configure 過後就會生成 Makefile 了, 裡面的 gcc 相關的參數,包括 lib 的路徑當然是 x86 下的了, 比如 /usr/local/lib, /usr/lib, /lib 什麼的, 改掉就是了。 或者註釋掉。

gcc 要換成 arm-linux-gcc 一類的 cross compiler,(如果不想每次都改, 參考下面的 include prerules.mk的做法)。總之, 這可讓你把 Makefile 掌握的很熟練,思路就是邊編譯,邊發現問題,再改,即使一開始 Makefile 不熟練,到後來,也熟練了。是個練習 Makefile 的好方式。

總之, 我們最後要的就是 Makefile,看你怎麼能得到它。
一個最標準的Makefile (去掉很多無用的東西)

透過 ./configure 生成的 Makefile,你會發現冗餘的地方非常多,其實關鍵的地方,就那麼20幾條,可以試著精簡一下,這樣對該軟體的組織架構會熟悉的快一些,畢竟 Makefile 反應了程序(具體就是 .c 和 .h )之間的依賴關係 。

openssh 的 Makefile 我沒有精簡過(當然要精簡也很容易), 舉個 telnetd 的例子,
說明一下:

----------------telnetd -------------------------------

#-----------------------------------------------------
TOPDIR := $(shell /bin/pwd)
TOPDIR := $(TOPDIR)/..

#prerules.mk 包含了這些變量的定義, 比如 $CC , $CPP , $CXX , $CFLAGS 等等。
#儘量不要在這裡出現 CC=arm-linux-gcc 這樣的定義,擴展性不好,儘量用全局變量,便於管理和拓展。
include $(TOPDIR)/prerules.mk
#-----------------------------------------------------

EXEC = telnetd

#好的 Makefile 都是這樣寫的, 也就是具體生成一個可執行文件或者 lib 庫, 需要哪些 .o , 這 些 .o 會依據後面的 .c.o : 規則來編譯出來的。
OBJS = telnetd.o state.o termstat.o slc.o sys_term.o \
utility.o global.o authenc.o logwtmp.o logout.o

#$(CC) 的編譯選項,一般程序自己帶的,不要改它,而且一般都是 += ,不要用 = ,
CFLAGS += -DEMBED -DPARANOID_TTYS -DUSE_TERMIO -DKLUDGELINEMODE -D_GNU_SOURCE -Wall

ifdef CONFIG_DEFAULTS_LIBC_UCLIBC
LDLIBS := -lutil $(LDLIBS)
endif

all: $(EXEC)
#很顯然 all 是最關鍵的了,也要發在最開始的地方。 這樣 make 就相當於 make all , 這是大家的潛規則。

.c.o:
$(CC) -c -o $@ $< $(CFLAGS) -I../include/ -I. -Ixxx 在 cross compile 的時候, 要在這個後面添上自己的標頭檔的路徑。

$(EXEC): $(OBJS) $(CC) $(LDFLAGS) -o $@ $(OBJS) $(LDLIBS$(LDLIBS_$@))
#這裡的LDFLAGS=-lcrypt -lzlib -L../lib -L. 總之根據自己的需要往裡面增加。

$(STRIP) telnetd
#如果不需要調試, 一定要經過 strip, 比如 15MB 的 file ,strip 過後,可能變成 3MB,還不影響功能。

install: cp $(EXEC) $(T_USBIN)
#自己寫install,不要用原來的,可以 copy 到自己的 ramdisk 中去。

clean: -rm -f $(EXEC) *.elf *.gdb *.[do]

$(OBJS): defs.h ext.h pathnames.h telnetd.h logwtmp.h logout.h

cross compile 成功後, 就萬事大吉了, 這才萬里長征的第一步。 剩下的也許更麻煩呢。

==================================================================

首先拿到一個軟體,我們首先要讓它在 pc 上 run 起來才行,至少我們要稍微瞭解了一下它, 才可以開始我們的 cross compile 的工作。
至少, 我們要瞭解要 run 這個程式,哪些東西是需要的,哪些是不需要的。
一開始,誰也不會瞭解的那麼多,只能一步步的拿到板子上跑跑看了。

準備工作:
1. 我們可以用 ldd 命令來查看某程式執行時需要哪些必要的 library。

2. 看看需要哪些配置文件,也就是 conf 文件。

其實如果想知道上面的這些,還有個辦法,就是先在 pc 上編譯, 安裝
./configure --prefix=/work/bob (改成你自己的目錄即可)
make && make install
看看/work/bob/下面到底生成了哪些 file , 你不就心裡有數了嗎。

==================================================================

先把你知道的程式 copy 到板子上去,執行一下,如果缺少哪些 library ,畫面上會秀出來一些錯誤訊息的。
缺什麼 ,就 copy 什麼到板子上好了,多半缺的都是庫(.so 文件) .

如果還是莫名其妙的出什麼問題(ps 結果就是沒有該 process),有可能是缺少什麼配置文件, 可以用 strace 來查查看。

==================================================================

如果程式執行的結果和 pc 上不太一樣 。 就要注意幾個根本的問題了。

1. 板子的 endian 是什麼類型的呢? x86 是 little endian,arm 的板子可能是 little endian,也可能是 big endian ,如果是 big endian , 就要注意了。要在程式裡面改,添加什麼 le32_to_cpu() 這樣的函數來轉換的。

2. 對齊問題 , x86 和 arm 的對齊處理方式是不一樣的。

3. 中文的問題, 有些程式需要支持中文,繁體,什麼的。pc 上可以, 拿到板子上就不可以了。你要考慮一下 glibc 上面是否支持 locale,libiconv 一類的 library。

==================================================================
生成動態鏈接庫的一個例子,也是標準的 Makefile

#Start of Makefile
#-----------------------------------------------------
TOPDIR := $(shell /bin/pwd)
TOPDIR := $(TOPDIR)/../../

include $(TOPDIR)/prerules.mk
#-----------------------------------------------------
SRCS = download.c curl_err.c DownloadStatusQuery.c
OBJS = download.o curl_err.o DownloadStatusQuery.o

CFLAGS += -I../../include -Wall # -g -ggdb

all: libdownload.so.1.0.0

#test_main:
# $(CC) $(CFLAGS) -I../../../include/ -o main main.c $(LIBS) -ldownload -L. -L../../../lib

%.o:%.c 或者 .c.o: 均可
$(CC) -c -o $@ $(CFLAGS)
$(CC) -c -o $@ $(CFLAGS) $< style="color:darkred;">lt;
libdownload.so.1.0.0 : $(OBJS)
$(CC) -shared -Wl,-soname,libdownload.so.1.0 -o libdownload.so.1.0.0 $(OBJS)
$(STRIP) libdownload.so.1.0.0
rm -rf libdownload.so.1.0
rm -rf libdownload.so
ln -s libdownload.so.1.0.0 libdownload.so.1.0
ln -s libdownload.so.1.0 libdownload.so
cp -afv libdownload.so* $(COMM_LIB_PATH)
cp -f download_operation.h $(COMM_INC_PATH)
cp -f operation.h $(COMM_INC_PATH)
cp -rf curl $(COMM_INC_PATH)
cp -f curl_err.h $(COMM_INC_PATH)
cp -f DownloadStatusQuery.h $(COMM_INC_PATH)

install: # copy到ramdisk裡面就好了
cp -afv libdownload.so* $(T_LIB) #用-afv 參數比較好,保證一模一樣

clean:
rm -rf libdownload.so*
rm -rf $(COMM_LIB_PATH)/libdownload.so*
rm -rf $(COMM_INC_PATH)/download_operation.h
rm -rf $(COMM_INC_PATH)/operation.h
rm -rf $(COMM_INC_PATH)/curl/
rm -rf $(COMM_INC_PATH)/curl_err.h
rm -rf $(COMM_INC_PATH)/DownloadStatusQuery.h
rm -rf *.o
===================
最後解釋一下:

$(CC) -shared -Wl,-soname,libdownload.so.1.0 -o libdownload.so.1.0.0 $(OBJS)

會得到文件,libdownload.so.1.0.0 ,

我們通常要作兩個鏈接

ln -s libdownload.so.1.0.0 libdownload.so.1.0
(這個是在板子上運行的時候一定要有的,因為,-Wl,-soname,libdownload.so.1.0 了,寫死了。 )

ln -s libdownload.so.1.0 libdownload.so
(這個是給別人鏈接的時候用的)

轉載[培訓新人系列之1] 作嵌入式系統,一定要學會裁減

轉載自: http://blog.chinaunix.net/u/22617/showart_372050.html
作者: bob_zhang2004@163.com
潤飾: Richman

作嵌入式系統,一定要學會裁減

嵌入式系統最典型的就是沒有掛硬碟(NAS 產品除外),通常只有 flash memory,基於 cost down 理由,一般用到 8MB。

所以擺在面前首要問題,就是軟體都移植上板子了,但全部都要放進去卻放不下怎麼辦?那產品就必然缺少某種功能。

裁減: 四條路

1. strip
strip 可以將執行檔中沒有用到的除錯資訊給拿掉,這對程式在執行是沒有影響的。
對於我們的 jk2410 就是 arm-9tdmi-linux-gnu-strip。
比如 sshd, 可以這樣做
arm-9tdmi-linux-gnu-strip sshd
也可以加萬用符號
arm-9tdmi-linux-gnu-strip *

2. 一個一個往板子放
初學者總是
./configure --prefix=/work/bob ...一堆交叉編譯參數 && make && make install

結果,有用沒有用的,通通 copy 到 /work/bob/下面來了。這顯然不是嵌入式之道,如果都這麼玩,板子的 flash 再大,也是放不下的。

要考慮哪些是有用的,哪些是沒有用的,舉個最簡單的例子,man 這個目錄肯定沒有用,你 copy到板子上去幹嘛呢?

我的思路就是一個一個的往板子裡面放,「需要的一個不少, 不需要的一個不多」。

下面的例子,可能我的記性有誤,但差不多就這個意思吧!

先執行 mysqld , 系統提示少了某些 *.so 文件, 我就 copy 到板子(也可以用 nfs)

再執行發現少了 /sbin/xx 文件,再 copy 過來

再執行,提示必須建立某些資料庫,然後我把相關腳本 copy 到板子上去。

又發現 hostname 好像不對,再設置 hostname。

再執行,發現/tmp/權限不夠,再 chmod -R 777 /tmp/

再執行,mysqld --user=root , 然後 ps ,怎麼還是看不到 mysqld,

最後使出殺手鐧(絕對必殺):strace
strace -f -F -o bob.log mysqld --user=root

發現好像說是沒有/dev/urandom,好傢伙,那就 mknod 做一個給它好了。


最後終於跑起來了。在上面的過程中,發現好多東西都沒有用,我記錄下來,重新修改 Makefile,make install的時候, 只 copy 剛才需要的 file 。而且一定要先 strip 過。

3. 改 code
這步,就比較高級一些了。如果上面兩條都做過了。size 還是太大,沒有辦法,只能改 code 了。 把我們用不到的功能相對應的 code通通剛除掉!

比如 mysql,有些功能我們就不需要,乾脆刪掉好了。編譯之後,空間又小了很多。

看看 kernel 就是個典型的例子, 400多MB 的 code,編譯出來的 uImage 才 1M,奇蹟!

4. 換大點的 flash
My God! 經過上面三條,size 還是太大,仍然放不下,沒有辦法了,找老闆:「老闆,我的 flash 太小了,放不下某個功能的 binary,強烈要求換一個大點的 flash」。

星期五, 4月 11, 2008

initramfs 簡介,一個新的 initial RAM disks 的模型

譯自
http://linuxdevices.com/articles/AT4017834659.html
https://landley.net/writing/rootfs-intro.html
by Rob Landley, TimeSys (Mar. 15, 2005)

initramfs 簡介,一個新的 initial RAM disks 的模型

問題

當 Linux 核心啟動系統,它必須找到並執行第一個使用者程式,通常是 init。使用者程式存在檔案系統,故 Linux 核心必須找到並掛上第一個(根)檔案系統,方能成功開機。

通常,可用的檔案系統都列在 /etc/fstab,所以 mount 可以找到它們。但 /etc/fstab 它本身就是一個檔案,存在檔案系統中。找到第一個檔案系統成為雞生蛋蛋生雞的問題,而且為了解決它,核心開發者建立核心命令列選項 root=,用來指定 root 檔案系統存在哪個裝置。

十五年前,root= 可以很容易地解譯。它可以是軟碟或硬碟上的分割區。如今 root 檔案系統可以存在各種不同類型的硬體(SCSI, SATA, flash MTD) ,或是由不同類型硬體所建立的 RAID 上。它的位置隨著不同啟動而不同,像是可熱插拔的 USB 裝置被插到有多個 USB 孔的系統上 - 當有多個 USB 裝置時,哪一個是正確的?root 檔案系統也可能被壓縮(如何?),被加密(用什麼 keys?),或 loopback 掛載(哪裡?)。它甚至可以存在外部的網路伺服器,需要核心去取得 DHCP 位址,完成 DNS lookup,並登入到遠端伺服器(需帳號及密碼),全部都在核心可以找到並執行第一個 userspace 程式。

如今,root= 已沒有足夠的資訊。即使將所有特殊案例的行為都放進核心也無法幫助裝置列舉,加密金鑰,或網路登入這些隨著系統不同而不同的系統。更糟的是,替核心加入這些複雜的工作,就像是用組合語言寫 web 軟體 - 可以做到,但使用適當的工具會更容易完成。核心是被設計成服從命令,而不是給命令。

為了這個不斷增加複雜度的工作, 核心開發者決定去尋求更好的方法來解決這整個問題。

解決方法

Linux 2.6 核心將一個小的 ram-based initial root filesystem(initramfs) 包進核心,且若這個檔案系統包含一隻程式 /init,核心會將它當作第一隻程式執行。此時,找尋其他檔案系統並執行其他程式已不再是核心的問題,而是新程式的工作。

initramfs 的內容不需是一般功能。若給定的系統的 root 檔案系統存在一個加密過的網路區塊裝置,且網路位址、登入、加密金鑰都存在 USB 裝置裡的檔案 "larry" (需密碼方能存取),系統的 initramfs 可以有特殊功能的程式,它知道這些事,並使這可以運作。

對系統而言,不需要很大的 root 檔案系統,也不需要定址或切換到任何其他 root 檔案系統。

這跟 initrd 有何不同?

Linux kernel 已經有方法提供 ram-based root filesystem,initrd 機制。對 2.4 及更早的 kernel 來說,initrd 仍然是唯一的方法去做這一連串的事。但 kernel 開發者為了幾個原因而選擇在 2.6 實作一個新的機制。

ramdisk 對上 ramfs

ramdisk (如 initrd) 是 ram based 區塊裝置,這表示它是一塊固定大小的記憶體,它可以被格式化及掛載,就像磁碟一樣。這表示 ramdisk 的內容需先格式化並用特別的工具(像是 mke2fs 及 losetup)做前置作業,而且如同所有的區塊裝置,它需要檔案系統驅動程式在執行時期做翻譯。這也有人工的大小限制不論是浪費空間(若 ramdisk 沒有滿,已被佔用的額外的記憶體也不能用來做其他事)或容量限制(若 ramdisk 滿了,但其他仍有閒置的記憶體,也不能不經由重新格式化將它擴展)。

但實際上 ramdisks 浪費更多的記憶體在快取上。Linux 被設計成將所有從區塊裝置讀進來或寫出去的檔案及目錄做快取,所以 Linux 會複製資料到 ramdisk 及從 ramdisk 複製資料到 "page cache"(對於檔案資料),及"dentry cache"(對於目錄)。ramdisk 偽裝成區塊裝置的最大缺點就是被當作(需要 cache 的)區塊裝置(i.e. 白白浪費了記憶體)(謝謝:Wenkui Liang)
但 ramdisk 實際上浪費更多記憶體於快取上。Linux 被設計為將所有的檔案及目錄做快取,不論是對區塊的讀出或寫入,所以 Linux 複製資料到 ramdisk及從 ramdisk 複製資料出來,page cache 給 file data 用,而 dentry cache 給目錄用。ramdisk 的下面則假裝為區塊裝置。

幾年前,Linus Torvalds 有一個靈巧的想法:Linux 的 快取是否可以被掛載像是一個檔案系統?只要保持檔案在快取中且不要將它們清除,直到它們被刪除或系統重新啟動?Linus 寫了一小段程式將快取包起來,稱它為 ramfs,而其他的 kernel 開發者建立一個加強版本稱為 tmpfs(它可以寫資料到 swap,及限制掛載點的大小,所以在它消耗完所有可用的記憶體前它會填滿)。initramfs 是 tmpfs 的實例。

這些 ram based 的檔案系統自己成長或縮小以符合資料所需的大小。增加檔案到 ramfs(或加大原有的檔案)會自動配置更多的記憶體,並刪除或截去檔案釋放記憶體。在區塊裝置及快取間沒有複製動作,因為沒有區塊裝置。在快取中的複製只是資料的複製。更棒的是這不是新的程式碼,而是已存在的 Linux 快取程式碼的新應用,這表示它幾乎沒有增加大小,非常簡單,且基於已經歷測試的基礎上。

系統使用 initramfs 作為它的 root 檔案系統甚至不需要將檔案系統驅動程式內建到 kernel,因為沒有區塊裝置要用來做檔案系統。只是存在記憶體中的檔案罷了。

initrd 對上 initramfs

在底層架構的改變是 kernel 開發者建立一個新的實作的理由,但當他們在那裡時他們清除了很多不好的行為及假設。

initrd 被設計為舊的 root= 的 root 裝置偵測程式碼的前端,而不是取代它。它執行 /linuxrc,這被用來完成設定功能(像是登入網路,決定哪個裝置含有 root 分割區,或用檔案做為 loopback 裝置),告訴 kernel 哪個區塊裝置含有真的 root 裝置(藉由寫人 de_t 數字到 /proc/sys/kernel/real-root-dev),且回傳給 kernel,所以 kernel 可以掛載真的 root 裝置及執行真的 init 程式。

這裡假設 read root device 是區塊裝置而不是網路分享出來的,同時也假設 initrd 不是它自己去做為真的 root 檔案系統。kernel 也不會執行 /linuxrc 做為特別的 process ID 1,因為這個 process ID(它有特別的屬性,像是做為唯一無法被以 kill -9 的 process) 被保留給 init,kernel 在它掛載真的 root 檔案系統後會等它執行。

用 initramfs,kernel 開發者移除所有的假設。當 kernel 啟動在 initramfs 外的 /init,kernel 即做好決定並回去等待接受命令。用 initramfs,kernel 不需要關心真的 root 檔案系統在哪裡,而在 initramfs 的 /init 被執行為真的 init,以 PID 1。(若 initramfs 的 init 需要不干涉特別的 PID 給其他程式,它可以用 exec() 系統呼叫,就像其他人一樣)

結語

傳統的 root= kernel 命令列選項仍然被支援且可用。

星期四, 4月 10, 2008

SL3516

Family ARM9TDMI

Architecture ARMv4T

Version ARM920T

Cache (I/D)/MMU 16 KB/16 KB, MMU

Typical MIPS @ MHz 200 MIPS @ 180 MHz

In application

Armadillo, GP32,GP2X (first core), Tapwave Zodiac (Motorola i. MX1), Hewlet Packard HP-49/50 Calculators, Sun SPOT, Samsung s3c2442 (HTC TyTN, FIC Neo1973[5])


SL3516


CPU0: D VIVT write-back cache


CPU0: I cache: 16384 bytes, associativity 2, 16 byte lines, 512 sets


CPU0: D cache: 8192 bytes, associativity 2, 16 byte lines, 256 sets


星期三, 4月 09, 2008

U-boot移植日記(s3c44b0)

摘自: http://bbs.chinalinux.com/blog.php?tid=176&starttime=0&endtime=0

幾經艱辛,終於基本完成了 u-boot 在 s3c44b0 的移植工作,在些記錄一下在移植過程中所碰到的困難和解決方法(一些心得),作為日後參考之用,也希望能夠幫到其它有需要的人 ^_^ 。
1. 來由:
在我搞完 ucos 後 ( 本來我是想學 uclinux 的,不過在對系統一無所知的情況下,還是先學一下 ucos 比較實際 ^_^ ,從中也可以對系統有個清晰的概 念 ) ,我意識到要搞系統的話一個功能強大的 bootloader 是必不可少的,而我的板上自帶的是 armboot (其實我個人覺得應用在 ARM 上的話 armboot 已經足夠了,畢竟 u-boot 也是從 armboot 中發展過來的,純屬個人意見),如果我的板上自帶光盤有已經移植好的 armboot 源代 碼供我參考的話,我想我也不會花這麼多時間去搞 u-boot ,可恨的是我的光盤上只有 armboot.bin 這個二進制文件,而沒有源文件,沒辦法,我下 定主意自己搞一個,考慮了一番後我選擇了 u-boot ,畢竟參考資料相對比較多,再我學完 u-boot 後再回頭看 armboot ,簡直是一個爐裡出的餅, 這是後話。
2. 準備:
說是容易,做起來卻挺難。因為編譯 u-boot 要在 linux 環境下,而不能在我們平時所熟悉的 ads 下那麼直觀。首先要建立好交叉編譯環境,這個交叉編 譯環境可以自己來做,不過完全沒必要,而且難度也挺大,一般是下載人家編譯好的工具。我剛開始在這裡就鬱悶了很久,現在會了以後覺得原來就是這麼簡單,在 些我把方法說清楚,希望不會再有人為這個問題鬱悶了 ^_^ :
1 )在網上下載一個 u-boot 源代碼,我用的是 1.1.2 版本的,最新的應該是 1.1.4 的吧,其實差不多,那就像我那樣下載一個 1.1.2 版本的吧。 把源文件解壓,這個應該不用說了吧,學過 linux 的人應該會,不會的話我想你繼續做下去也困難,那就先裝個 linux 用下吧(我用的是 RedHat 的, 哦對了,編譯程序是需要 gcc 編譯器的,所以安裝方式一定要選擇工作站哦 ^_^ )。好了,解壓後你發現在 u-boot.1.1.2 目錄下有 Makefile 這個文件吧?讓我們看看它裡面的內容,最簡單的方法就是 vi Makefile 了。我們要看的是它選擇的是哪一個交叉編譯器。可以看到這一項:
ifeq ($(ARCH),arm)
CROSS_COMPILE = arm-linux-
看到吧,也就是說這裡所用的交叉編譯器是 arm-linux-gcc 了,( u-boot 默認是用這個的,也有用 arm-elf-gcc 的,網上有個工具包 arm-elf-tools-20030314.sh, 我試過用它來編譯,沒有問題,順便提一下, arm-elf-gcc 是用來編譯 uClinux 內核的 工具來的)那你就下載一個 arm-linux- 的交叉編譯器吧,我是在網上下載 cross-2.95.3.tar.bz2 這個文件,然後解壓得到 2.95.3 版本的交叉編譯工具的,具體設置如下(參考網上資料):
2 )在宿主機上建立 arm-linux-gcc 交叉編譯環境
在 RedHat Linux 系統下以 root 用戶登錄,
將 cross-2.95.3.tar.bz2 文件複製到 / 目錄下,
安裝:
# tar jxvf cross-2.95.3.tar.bz2
這個命令會在你的 /usr/local/arm/2.95.3 目錄下安裝 arm-linux-gcc 交叉編譯程序,
然後在 PATH 變量中添加一項: /usr/local/arm/2.95.3/bin.
[root@localhost root]# export ATH=/usr/local/arm/2.95.3/bin:$PATH

把 PATH=/usr/local/arm/2.95.3/bin:$PATH 添加到 /ETC/bash_profile 文件中
或者
在 /etc/bashrc 文件中添加一項 :
export PATH=/usr/local/arm/2.95.3/bin:$PATH
測試:
把終端關閉,重新打開後執行如下命令:
# arm-linux-gcc –v
好了,建立好交叉編譯環境後可以試著編譯 u-boot 了

這裡提幾個注意點:
1. 不可用 winRAR 解壓 u-boot-1.1.2.tar.bz2 或 u-boot-1.1.2.tar.gz 這種文件(就個可能新手會犯,一般熟悉 linux 命令的人應該都不會這樣做吧,在此還是要提一下)
2. 可能下載的文件有一些中間文件會阻礙編譯的運行,所以在編譯前最好來個徹底清除,在 u-boot.1.1.2 目錄下運行命令: make distclean (其實這個命令在 Makefile 文件下就有)我當時為這個問題鬱悶了很久,希望你們不會像我這樣 ^_^ ) ;
3 ,有些人為了方便想在 cygwin 下編譯,但是經常在網上看到在這個虛擬平台下編譯有很多的問題,要配置的東西也多,而且好像我用過那個 vi 沒有 linux 環境下的好用,所以最好還是不要用這個軟件了吧,如果你真的離不開 windows 的話可以像我這樣裝個虛擬機,在虛擬機下再裝 linux 的系 統,具體參考這個網站): http://fedora.linuxsir.org/doc/vmware/
3 )好了,現在開始測試你的交叉編譯器搞好沒有。在 u-boot. 1.1.2 目錄下執行如下命令:
1)Make distclean ( 再次強調 )
2)Make B2_config( 隨便再個現成的試試 ^_^)
3)Make ( 沒錯的話應該會生成 u-boot.bin 文件,發生錯誤的話也不怕,只要細心看一下哪裡錯就行了, gcc 碰到錯誤後會退出編譯,所以可以一個個錯誤來 改,一般的問題都是沒找到編譯器(可能你沒裝或者裝的不對,例如人家用的是 arm-linux- 而你裝的是 arm-elf- ,如果你裝了的話看看你的環境 變量設好了沒有,前面有講,如果不關編譯器的事的話那就再看看,一般是文件的後綴不對,有些文件後綴是大寫的,例如 start.S 但是如果你的是 start.s 小寫的話那當然找不到(解決方法很,把它改成大寫就行了)。細心看吧,不用怕,它都有註明路徑,很容易可以找到的) )
如果以上步驟都無誤的話那麼恭喜你,你的交叉編譯環境可以用來編譯你的 u-boot 源代碼了,可以開始以下階段。

3. 移植:
說時遲那時快,現在開始移植工作 ( 以下是我一步步重新做一遍,力求說得詳細點,感謝我吧 ^_^)
我以 B2 板子的程序做為模板來做 .
#cd u-boot- 1.1.2
#cd board
#cp -R dave myboard ( 這是我取的板子名字,可以換上你的,但是後面的也要跟著來換哦 ^_^)
#cd myboard
#mv B2 myboards 3c 44b0 ( 自己取個板子名 )
#cd myboards 3c 44b0
# mv B2.c myboards 3c 44b0.c
修改 myboards 3c 44b0 裡面的 Makefile, 把 B2 改成 myboards 3c 44b0 ,編譯時如果報的其它類似找不到 B2 的錯誤也是把相應的 B2 改成 myboards 3c 44b0 來處理。

1 )其中的 myboards 3c 44b0.c 文件是板的初始化代碼,看一下就知道,根據你的板上自帶的 44binit.s

來修改吧。 memsetup.S 文件主要是存儲器的初始化設置,其實也是 44binit.s 裡面的一部分。
2 )其實 board 這裡要修改的不多,先跳過 flash 部分吧,我們來看一下 cpu 設置部分吧。
u-boot-1.1.2 裡面已經加入了對 s 3c 44b0 的支持,讓我們來看一下 cpu/s 3c 44b0 裡面的部分吧。
看到 start.S 這個文件了嗎?要修改的其實並不多,按照你的板設置一下中斷跳轉矢量就行了,或者上網查一下吧,應該很容易看明的。其中 cpu.c 這個 文件簡直不用修改,再來看一下 serial.c 這個文件吧,改一下波特率的設置就行,就是你用多少 M 的 CPU 頻率的話對應的波特率參數設置問題,其實 B2 已經做得不錯的了,很多子程序都不用自己寫的了 ^_^ ,在我的板上是這樣設置的 , 參考一下吧 :
#if CONFIG_S 3C 44B0_CLOCK_SPEED==66 ,把所有的這些 66 改成 60 ,原因,我的實驗板上用的頻率是 60 ( 44B0 最高頻率為 64M )。然後其它分頻係數,寄存器初始化設置,可以參考一下 44blib.c ,在這裡我給出我的設置出來吧,可以參考一下。

case 115200:
#if CONFIG_S 3C 44B0_CLOCK_SPEED==60
divisor = 32;

UFCON0 = 0x0;
ULCON0 = 0x03;
UCON0 = 0x245;
UBRDIV0 = divisor;

我在這方面算術不好,所以都是參考人家的。

3 )好,再加上個頭文件:
cd u-boot-1.1.2/include/configs
cp B2.h myboards 3c 44b0.h
這個頭文件其實要改的地方還挺多的,我等下再說怎樣修改。先回到 u-boot.1.1.2 目錄,

4 )在 Makefile 裡面加上這部分,不會的話就模仿 B2 來寫吧 ^_^
在 B2 的這部分文件
B2_config:unconfig
@./mkconfig $(@:_config=) arm s 3c 44b0 B2 dave
後面加上這部分:
myboards 3c 44b0_config:unconfig
@./mkconfig $(@:_config=) arm s 3c 44b0 myboard 3c 44b0 myboard

切記在 @./mkconfig $(@:_config=) arm s 3c 44b0 myboard 3c 44b0 myboard 前面的是 Tab 來的,萬萬不能用空格代替,因為它是靠這個來識別命令的!

5 )好,現在可以在 u-boot-1.1.2 目錄下執行如下命令:
Make distclean (還是用這個吧,比較徹底)
Make myboards 3c 44b0_config
Make
看看有沒有錯,有錯的話按著提示來改,如果沒錯的話應該就能生成 u-boot.bin 這個文件,現在還不能用哦,因為這幾是 B2 的一個仿製品而已(註:在我的機上到這一步可沒有報錯哦,你一步步按著來做的話應該也不會有什麼錯誤吧 ^_^ )。


6 )好,現在繼續修改 u-boot-1.1.2/include/configs/myboards 3c 44b0.h 這個文件。
#define CONFIG_INIT_CRITICAL1 這個在 cpu/s 3c 44b0/start.S 裡面用到,如果你的 u-boot 程序不是在 sdram 中調試而是固化到 flash 中運行的話,這個必不可少。
找到 #define CONFIG_B2 1 把 B2 改成 myboards 3c 44b0 吧(不然就不會編譯你的板了)
找到 #define CONFIG_S 3C 44B0_CLOCK_SPEED 75 你的 44b0x 應該沒有 75M 吧 我的是改成 60 的
找到 Size of malloc() pool 這部分設置,改成這樣吧,反正我是照著人家來做的,你自己研究下吧 ^_^ 。

#define CFG_MONITOR_LEN(256 * 1024)/* Reserve 256 kB for Monitor*/
#define CFG_ENV_SIZE (64*1024)/* 1024 bytes may be used for env vars*/
#define CFG_MALLOC_LEN(CFG_ENV_SIZE + 128*1024 )
#define CFG_GBL_DATA_SIZE128/* size in bytes reserved for initial data */
#define CFG_ENV_IS_IN_FLASH 1 這個必不可少,如果你想把你的參數保存到 flash 的話(有些板是保存到 EEPRAM 中去的,但是 s 3c 44b0 的話還是保存到 flash 吧)
#define CFG_ENV_ADDR(PHYS_FLASH_1+0x40000) 這個就是你的參數保存在 flash 裡的起始地址了
#define CFG_ENV_OFFSET0x40000 這個我後來看它源程序發現如果你上一步沒有設置它的起始地址的話就會用它來作默認地址的了
#define CONFIG_AUTO_COMPLETE

其它地方沒有深究哦,有些好像不要也行,你就試試吧。

找到 Hardware drivers 部分,這應該是網絡芯片設置吧,參考一下這個吧(要看芯片的):
#define CONFIG_DRIVER_RTL8019 這個就要看你的板上用的是什麼網卡了(這個是台灣出的,有 10M )
#define RTL8019_BASE0x06000000 這個是網卡相就寄存器的起始地址
以下部分我試過不要也行,你試下吧
#define RTL8019_BUS320
#define CONFIG_SMC_USE_16_BIT
#undef CONFIG_SHOW_ACTIVITY
#define CONFIG_NET_RETRY_COUNT10 應該是重試的次數吧

#define CONFIG_BAUDRATE115200 設置波特率

#define CONFIG_COMMANDS( CONFIG_CMD_DFL | \
CFG_CMD_DATE | \
CFG_CMD_ELF| \
CFG_CMD_NET | \

CFG_CMD_EEPROM| \
CFG_CMD_I 2C | \
CFG_CMD_FAT | \
CFG_CMD_JFFS2)
把 CFG_CMD_EEPROM 改成 CFG_CMD_FLASH 吧,雖然不改也是可以的,具體沒考究。

以下是板上 env 參數設置,看一下吧,其實我覺得瞭解一下就行的了,只是一些初始設置值,以後可以用命令 setenv saveenv 來修改的。
#define CONFIG_BOOTDELAY3 這個就是運行 bootcmd 之前的等待時間
#define CONFIG_BOOTARGS "devfs=mount root=ramfs console=ttyS0,115200" 引導 uClinux 的時候傳遞的參數,不會就先不用管它也行。
#define CONFIG_ETHADDR00:50:c2:1e:af:fb 網卡的物理地址 MAC
#define CONFIG_NETMASK 255.255.255.0 掩碼地址,設置過 ip 的人都應該知道吧
#define CONFIG_IPADDR 192.168.0.30 這是你板上網卡 8019 的 ip 地址
#define CONFIG_SERVERIP192.168.0.10 這是你宿主機的 ip 地址,以後用 tftp 下載的時候用到,一定要跟你的宿主機一致才行。
#define CONFIG_BOOTFILE"u-boot.bin" 這個就是你要下載文件的默認名字
#define CONFIG_BOOTCOMMAND"bootm 0x50000" 這是 bootdelay 後運行的命令

Miscellaneous configurable options 部分,參考一下吧:
#defineCFG_LONGHELP/* undef to save memory*/
#defineCFG_PROMPT"s 3c 44b0=>" 這是進入命令模式下的提示符,改個帥一點的吧
#defineCFG_CBSIZE256/* Console I/O Buffer Size*/
#defineCFG_PBSIZE (CFG_CBSIZE+sizeof(CFG_PROMPT)+16) /* Print Buffer Size */
#defineCFG_MAXARGS 100/* max number of command args*/
#define CFG_BARGSIZECFG_CBSIZE/* Boot Argument Buffer Size*/

#define CFG_MEMTEST_START 0x 0C 400000/* memtest works on*/
#define CFG_MEMTEST_END0x 0C 800000/* 4 ... 8 MB in DRAM*/
#undef CFG_CLKS_IN_HZ/* everything, incl board info, in Hz */
#defineCFG_LOAD_ADDR0x 0c 008000 默認的下載地址
#defineCFG_HZ1000/* 1 kHz */
#define CFG_BAUDRATE_TABLE { 9600, 19200, 38400, 57600, 115200 } 可供選擇的波特率

Physical Memory Map 部分,比較重要,修改你的 sdram 和 flash 的地址和容量。
#define CONFIG_NR_DRAM_BANKS1 我們只佔用了一個 Bank 用來映射 sdram
#define PHYS_SDRAM_10x 0c 000000 sdram 的起始地址
#define PHYS_SDRAM_1_SIZE0x00800000 sdram 的容量( 8M )
#define PHYS_FLASH_10x00000000 flash 的起始地址
#define PHYS_FLASH_SIZEflash 的容量( 2M )
#define CFG_FLASH_BASEPHYS_FLASH_1 定義多個名字而已,其它地方會用到

FLASH organization 部分,看註釋應該知道了吧,參考一下:
#define CFG_FLASH_ERASE_TOUT4120000/* Timeout for Flash Erase (in ms)*/
#define CFG_FLASH_WRITE_TOUT4000/* Timeout for Flash Write (in ms)*/

按著來一步步的做應該不難,這裡提一下 vi 程序的用法,其實在 google 一搜就找到了,不過為了方便大家,還是說一聲吧,
在命令模式下:
按 / xxx 再回車即可搜索到你所需要的內容( xxx ),再按 n 搜索下一個,按 shift+n 搜索上一個
按 :xxx 即可跟到你想要的行
按 :set nu 顯示行號
其它查書都可以找到就不說了。

做到這個時候,你可以再編譯一下,看有沒有錯,這一步我就沒有幫你們做了,不過我覺得應該不會有問題吧,下載到 ram 中運行,看看效果。

7 )終於到了 flash 的設置部分了,這完全是我個人悟出來的,網上資料好像講得不是先清楚。
首先介紹一下 flash 的識別吧,每塊 flash 都有一個 id ,前部分用來說明生產廠家,後部分用來說明它的容量,類型,位數等。它們的定義是在 u-boot-1.1.2/include/flash.h 中,就以我的 ssts9vf1601 為例:
#define SST_MANUFACT0x00BF00BF 這是生產廠家 id
#define SST_ID_xF16010x234B234B 這是它的型號,容量,位數等 id
#define FLASH_SST 160A 0x0046 這個我還說不清楚,有個要注意的問題是像 sst160 是不能用奇地址的,我做的過程中是把 SST 160A 改成 SST1601 的,懶得幫它創一個
好了,相信你已經找到你的板上所用的 flash 對應的 id 號了吧?現在就來談談怎麼改。
先進入 u-boot-1.1.2/board/myboards 3c 44b0/common/flash.c
它裡面已經幫 SST 160A 設置好了,我的做法是把 SST 公司的 160A 都改成 1601 ,是不是很簡單,當然你也可以幫 1601 再寫一分,但是我是個懶人,所以我就樣做了 ^_^

到這裡還有個問題沒提到的,就是如果你重新用 setenv saveenv 設置了參數,但是復位後會發現怎麼沒有保存到的(不信你試試看)。其實我是故意留到這裡講的,應該它不會報錯,可以說是比較隱秘的問題,所以我故意放到這裡來說,以引起你的重視。
解決方法: vi u-boot-1.1.2/board/myboard/common/flash.c
找到這個函數: write_buff
裡面有這句話: #ifdef CONFIG_B2
要把 B2 改了,因為我們的板不叫 B2 ,那叫什麼呢?原來是在這裡定義的: u-boot-1.1.2/include/configs/myboards 3c 44b0.h
裡面有這句話: #define CONFIG_HFRK 你不喜歡 HFRK 這個名字也行,可以改成別的名字,只不過相應地前面的 B2 也要改成這個名字而已。

4. 後記:
本來是想剛做好的時候寫的,但是後來發現有些功能實現不了,所以就停住了筆,等我搞好了以後,又急著去學習 uClinux 的移植,真的很忙,現在終於 抽空把它寫完。雖然有些地方還沒說清楚(畢竟我對它的瞭解還不是很深,但我相信在我以後移植系統的過程中會逐步加深對它的瞭解),我還是希望它能成為最詳 盡的 u-boot 移植新手指導,對 u-boot 移植的初學者起到實質性的作用,這樣就不枉我花了這麼多的心思來寫這個文檔。

參考資料:
http://blog.21ic.com/more.asp?name=sockit&id=8509
我所認為的最有奉獻精神,寫得最詳細的記錄,在此表示我深深的敬意!

嵌入式系統中U-Boot基本特點及其移植方法

作者:上海大學 宋國軍 張侃諭 林學龍

引言

Bootloader(引導裝載器)是用於初始化目標板硬件,給嵌入式操作系統提供板上硬件資源信息,並進一步裝載、引導嵌入式操作系統運行的固件。在嵌入式系統開發過程中,很多情況都會涉及底層Bootloader的移植問題, 即使在有些已有Bootloader的參考開發板上也存在這種可能。概括來說, 如下情況會考慮進行Bootloader的移植工作。

① 在自主設計的目標板上,用於引導嵌入式操作系統及其應用。
② 在廠家未提供Bootloader源碼的參考板上,遇有如下情形之一:

a.在實際應用中需要添加或修改一些功能;
b.為了給自行設計主板移植Bootloader提供參考,先在參考板上進行移植以積累經驗。

另外,從嵌入式系統實際開發角度講, 嵌入式操作系統的引導、配置甚至應用程序的運行狀況都和bootloader有一定的關聯,可以說,掌握Bootloader移植是順利進行嵌入式系統開發的重要利器。

與常見的嵌入式操作系統板級支持包 BSP 相比,Bootloader 與底層硬件更為相關,即每個不同配置的目標板基本都有不同的 Bootloader。因為 Bootloader 往往更依據量體裁衣、定身製作的原則,以滿足要求的最小化代碼存放在啟動ROM 或Flash中。

雖然,自行編寫Bootloader未嘗不可,但從可利用的資源和實際項目開發考慮,採用移植已有的Bootloader源碼來解決這一問題更符合大多數項目的開發要求。



1. U-Boot簡介

U—Boot,全稱Universal Boot Loader,是遵循GPL條款的開放源碼項目,從FADSROM、8xxROM 、PPCBOOT逐步發展演化而來,其源碼目錄、編譯形式與Linux內核很相似。事實上,不少U—Boot源碼就是相應Linux內核源程序的簡化,尤其是一些設備的驅動程序,從U-Boot源碼的註釋中能體現這一點。但是U-Boot不僅僅支持嵌入式Linux系統的引導,當前,它還支持NetBSD。VxWorks、 QNX、RTEMS、ARTOS、LynxOS嵌入式操作系統。其目前要支持的目標操作系統包括0P enB S D 、NetBSD、FreeBSD、4 4BSD 、Linux、SVR4、Esix、Solaris、Irix、SCO、Dell、NCR、VxWorks、LynxOS、pSOS、QNX、RTEMS 和ARTOS。這是u-Boot中Universal的一層含義。另外一層含義則是U-Boot除了支持PowerPC系列的處理器外,還能支持 MIPS、x86、ARM 、Nios、XScale等諸多常用系列的處理器。這兩個特點正是U-Boot項目的開發目標,即支持儘可能多的嵌入式處理器和嵌入式操作系統。就目前來看,U-Boot對PowerPC系列處理器支持最為豐富, 對Linux的支持最完善。其它系列的處理器和操作系統基本是在2002年1 1月PPCBOOT改名為U-Boot 後逐步擴充的。從PPCBOOT向U—Boot的順利過渡,很大程度上歸功於U-Boot的維護人,德國DENX軟件工程中心的Wolfgang Denk(以下簡稱w.D)本人精湛的專業水平和持著不懈的努力。當前,u-BOOt項目在他的領軍下,眾多有志於開放源碼Boot loader移植工作的嵌入式開發人員, 正如火如荼地將各個不同系列嵌入式處理器的移植工作不斷展開和深入, 以支持更多嵌入式操作系統的裝載與引導。


2. U-Boot主要目錄結構

* board - 目標板相關文件,主要包含SDRAM、Flash驅動;

* common - 獨立於處理器體系結構的通用代碼, 如內存大小探測與故障檢測;

* cpu - 與處理器相關的文件, 如mpc8xx子目錄下含串口、網口、LCD 驅動及中斷初始化等文件;

* driver - 通用設備驅動,如CFI Flash驅動(目前對Intel Flash支持較好)

* doc - U-Boot的說明文檔;

* examples - 可在U-Boot下運行的示例程序;如hello_world.c, timer.c;

* include - U-Boot頭文件,configs子目錄下與目標板相關的配置頭文件是移植過程中經常要修改的文件;

* lib-XXX - 處理器體系相關的文件, 如lib-PPC, lib-arm 目錄分別包含與PowerPC、ARM體系結構相關的文件;

* net - 與網絡功能相關的文件目錄,如bootp、nfs、 tftp;

* post -上電自檢文件目錄, 尚有待於進一步完善;

* rtc - RTC驅動程序;

* tools - 用於創建U-Boot S-Record和BIN image文件的工具。


3. U-Boot支持的主要功能


U-Boot可支持的主要功能如下所列。

系統引導 支持NFS掛載、RAMDISK 系統引導 (壓縮或非壓縮)形式的根文件系統

支持NFS掛載,從Flash中引導壓縮或非壓縮系統內核

基本輔助 強大的操作系統接口功能,可靈活設置、傳遞多個關鍵參數給操作系統, 適合系統在不同開發階段的調試要求與產品發佈,尤其對Linux支持最為功能強勁

支持目標板環境參數的多種存儲方式,如Flash、NVRAM、EEPROM

CRC32校驗,可校驗Flash中內核、RAMDISK image是否完好

設備驅動 串口、SDRAM、Flash、以太網、LCD、NVRAM、EEPROM、鍵盤、USB、PCMCIA、PCI、RTC等驅動支持

上電自檢功能 SDRAM、Flash大小自動檢測;SDRAM 故障檢測;CPU型號

特殊功能 XIP內核引導



4. U-Boot移植過程


① 獲得發佈的最新版本U-Boot源碼,與Linux內核源碼類似,也是bzip2的壓縮格式。可從U-Boot的官方網站 http://sourceforge.net/projects/u-boot 上獲得。

② 閱讀相關文檔,主要是U-Boot源碼根目錄下的README文檔和U-Boot官方網站的DULG(The DENX U-Boot and Linux Guide)文檔(http://www.denx.de/twiki/bin/view/DULG/Manual)。尤其是DULG文檔,對如何安裝建立交叉開發環境和解決U-Boot移植中常見問題,都一一給出了詳盡說明。

③ 訂閱U-Boot用戶郵件列表( http://lists.sourceforge.net/lists/listinfo/u-boot-users)。當在移植U-Boot過程中遇有問題,在參考相關文檔和搜索U-boot-users郵件檔案庫(http://sourceforge.net/mailarchive/forum.php? forum-id=l2898)仍不能解決時,第一時間提交所遇到的問題, 眾多U-Boot開發人員會迅速排查問題,而且W.D本人很有可能會直接參與指導。

④ 在建立的開發環境下進行移植工作。絕大多數的開發環境是交叉開發環境。在這方面,DENX和MontaVi sta均提供了完整的開發工具集。

⑤ 在目標板與開發主機間接入硬件調試器。這是進行U-Boot移植應當具備且非常關鍵的調試工具。因為在整個U-Boot的移植工作中,尤其是初始階段,硬件調試器是我們瞭解目標板真實運行狀態的唯一途徑。在這方面, W .D 本人和眾多嵌入式開發人員傾向於使用BDI2000。一方面,其價格不如ICE調試器昂貴,同時其可靠性高,功能強大,完全能勝任移植和調試U-Boot。另外, 網上也有不少關於BDI2000調試方面的參考文檔。

⑥ 如果在參考開發板上移植U-Boot,可能需要移除目標板上已有的Boot loader。可以根據板上Boot loader的說明文檔,先著手解決在移除當前Boot loader的情況下,如何進行恢復,以便今後在需要場合能重新裝入原先的Boot loader。

5. U-Boot移植方法

當前,對於U-Boot的移植方法,大致分為兩種。一種是先用BDI2000創建目標板初始運行環境,將U-Boot鏡像文件u-boot.bin下載到目標板 RAM中的指定位置,然後,用BDI2000進行跟蹤調試。其好處是, 不用將Uboot鏡像文件燒寫到Flash中去。但弊端在於,對移植開發人員的移植調試技能要求較高,BDI2000的配置文件較為複雜。另外一種方法是用BDI2000先將U-Boot鏡像文件燒寫到Flash中去,然後利用GDB和BDI2000進行調試。這種方法所用的BDI2000配置文件較為簡單,調試過程與U-Boot移植後運行過程相吻合。即U-Boot先從Flash中運行,再重載至RAM 中相應位置,並從那裡正式投入運行。唯一感到有些麻煩的就是需要不斷燒寫Flash。但考慮到Flash常規擦寫次數基本為l 0萬次左右,作為移植U-Boot,不會佔用太多的次數,應該不會為Flash燒寫有什麼擔憂。同時,w.D本人也極力推薦使用後一種方法。筆者建議,除非是U-BOot移植資深人士或有強有力的技術支持, 建議採用第二種移植方法。

6. U-Boot移植主要修改的文件
從移植U-Boot最小要求,U-Boot能正常啟動的角度出發, 主要考慮修改如下文件。
.h 頭文件,如include/congs/RPxlite.h。可以是U-Boot源碼中已有的目標板頭文件,也可以是新命名的配置頭文件; 大多數的寄存器參數都是在這一文件中設置完成的。
.c 文件,如board/RPXlite/RPXlite.C。它是SDRAM 的驅動程序,主要完成SDRAM 的UPM 表設置, 上電初始化。
③ Flash的驅動程序,如board/RPXlite/flash.c 或 common/cfi-flash.c。可在參考已有Flash驅動的基礎上, 結合目標板Flash數據手冊,進行適當修改;
④ 串口驅動,如修改cpu/mpc8xx/seria1.c串口收發器芯片使能部分。

7. U-Boot移植要點
① BDI2000的配置文件。如果採用第二種移植方法,即先燒入Flash的方法,配置項只需很少幾個,就可以 進行U-Boot的燒寫與調試了。對PPC 8xx系列的主板,可參考DULG文檔中TQM8xx的配置文件進行相應的修改。下面,筆者以美國Embedded Planet公司的RPXlite Dw 板為例,給出在嵌入式Linux交叉開發環境下的BDI2000參考配置文件以作參考。
;bdiGDB configuration file for RPXlite DW or LITE DW
[INIT]
;init core register
WSPR 149 0x2002000F ;DER :set debug enable ;register
WSPR 149 0x2002000F ;DER :enable SYSIE for BDI ;Flash Program
WSPR 638 oxFA200000 ;IMMR :internal memory at ;0xA200000
WM 32 oxFA200004 0xFFFFFF89 ;SYPCR
[TARGET]
CPUCLOCK 4000000 ;the CPU clock rate after processing
;the init list
BDIMODE AGENT :the BDI WOrking mode
(LOADONLY | AGENT)
BREAKMODE HARD ;SOFT or HARD,HARD uses PPC
;hardware breakpoints
[HOST]
IP l72.16.115.6
FILE ulmage.litedw
FORMAT BIN
LOAD M ANUAL ;load code MANUAL or AUTO after rese
DEBUGPORT 2001
START 0x0100
[FLASH]
CHIPTYPE AM29BX8 ;Flash type(AM29F l AM29BX8
;AM29BX16 f I28BX8 f 128BX16)
CHIPSIZE 0x400000 ;The size of one flash chip in bytes
BUSWIDTH 32 ;The width of the flash memory bus
;inbits(8f 16f 32)
WORKSPACE 0xFA202000 ;RAM buffer for fast flash
;programming
FILE u-boot.bin ;The file to program
FORMAT BIN 0x00000000
ERASE 0x00000000 BLOCK
ERASE OxO0008000 BLOCK
ERASE 0x00010000 BL0CK
ERASE 0x000l8000 BLOCK
[REGS]
DMM 1 OxFA200000
FILE reg823.def
② U-Boot移植參考板,這是進行U-Boot移植首先要明確的。可以根據目標板上CPU、Flash、SDRAM的情況,以儘可能相一致為原則,先找出一個與所移植目標板為同一個或同一系列處理器的u-Boot支持板為移植參考板。如RPXlite DW 板可選擇U-Boot源碼中RPXlite板作為U-Boot移植參考板。對U-Boot移植新手, 建議依照循序漸進的原則,目標板文件名暫時先用移植參考板的名稱,在逐步熟悉U-BOOt移植基礎上,再考慮給目標板重新命名。在實際移植過程中,可用Linux命令查找移植參考板的特定代碼,如grep -r RPXlite ./可確定出在U-Boot中與RPXlite板有關的代碼,依此對照目標板實際進行屏蔽或修改。同時,應不侷限於移植參考板中的代碼, 要廣泛借鑑U-BOOt中已有的代碼, 更好地實現一些具體的功能。

③ U-Boot燒寫地址。不同目標板,對U-Boot在Flash中存放地址的要求不盡相同。事實上,這是由處理器中斷復位向量來決定的,與主板硬件相關。對MPC8xx主板來講,就是由硬件配置字(HRCW)決定的。也就是說,U-Boot燒寫具體位置是由硬件決定的,而不是程序設計來選擇的。程序中相應U-Boot起始地址必須與硬件所確定的硬件復位向量相吻合,如RPXlite DW 板的中斷復位向量設置為0x00000100。因此,U-Boot的BIN image 文件必須燒寫到Flash的起始位置。事實上,大多數的PPC系列的處理器中斷復位向量是0x00000100和0xfff00100。這也是一般所說的高位啟動和低位啟動的Bootloader所在位置。可通過修改u-BOot源碼<目標板>.h頭文件中CFG MONITOR BASE和board/<目標板>/config.mk中的TEX T — BASE的設置來與硬件配置相對應。

④ CPU寄存器參數設置。根據處理器系列、類型不同, 寄存器名稱與作用有一定差別,必須根據目標板的實際進行合理配置。一個較為可行和有效的方法是,借鑑參考移植板的配置,再根據目標板實際,進行合理修改。這是一個較費功夫和考驗耐力的過程,需要仔細對照處理器各寄存器定義、參考設置、目標板實際作出選擇並不斷測試。MPC 8XX處理器較為關鍵的寄存器設置為SIUMCR、PLPRCR、SCCR、BRx和ORx。

⑤ 串口調試。能從串口輸出信息,即使是亂碼,也可以說U.Boot移植取得了實質性突破。依據筆者調試經歷,串口是否有輸出,除了與串口驅動相關外,還與Flash相關的寄存器設置有關。因為U-Boot是從Flash中被引導啟動的,如果Flash設置不正確,U-Boot代碼讀取和執行就會出現一些問題。因此,還需要就Flash的相關寄存器設置進行一些參數調試。同時,要注意串口收發芯片相關引腳工作波形。依據筆者調試情況,如果串口無輸出或出現亂碼, 一種可能就是該芯片損壞或工作不正常。

⑥ 與啟動Flash相關的寄存器BR0、OR0的參數設置,應根據目標板Flash的數據手冊與BR0和OR0的相關位含義進行合理設置。這不僅關係到Flash能否正常工作, 而且與串口調試有直接的關聯。

⑦ 關於CPLD電路。目標板上是否有CPLD電路絲毫不會影響U-Boot的移植與嵌入式操作系統的正常運行。事實上,CPLD電路是一個集中將板上電路的一些邏輯關係可編程設置的一種實現方法。其本身所起的作用就是實現一些目標板所需的脈衝信號和電路邏輯, 其功能完全可以用一些邏輯電路與CPU口線來實現。

⑧ SDRAM的驅動。串口能輸出以後,U-Boot移植是否順利基本取決於SDRAM 的驅動是否正確。與串口調試相比,這部分工作更為重要,難度更大。MPC8xx目標板SDRAM 驅動涉及三部分。一是相關寄存器的設置;二是UPM 表;三是SDRAM 上電初始化過程。任何一部分有問題,都會影響U-Boot、嵌入式操作系統甚至應用程序的穩定、可靠運行。所以說,SDRAM 的驅動不僅關係到U-Boot本身能否正常運行, 而且還與後續部分相關, 是相當關鍵的部分。

⑨ 補充功能的添加。在獲得一個能工作的U-Boot後, 就可以根據目標板和實際開發需要, 添加一些其它功能支持, 如以太網、L CD 、NVRAM 等。與串口和SDRAM 調試相比,在已有基礎之上,添加這些功能還是較為容易的。大多只是在參考現有源碼的基礎上,進行一些修改和配置。另外, 如果是在自主設計的主板上移植U-Boot, 那
麼除了考慮上述軟件因素以外, 還需要排查目標板硬件可能存在的問題, 如原理設計、PCB布線、元件好壞。
在移植過程中, 敏銳判斷出故障態是硬件還是軟件問題, 往往是關係到項目進度甚至移植成敗的關鍵, 相應
難度會增加許多。

結語
完成一個目標板的移植工作後,可考慮將移植結果以補丁的形式發送到U-Boot用戶郵件列表,尤其是一些參考板的移植結果。這是使用GPL代碼並遵循GPL條款的體現。可在閱讀 README相關補丁說明的基礎上,添加適當的註釋,將自己列入光榮榜(CREDITS)。如果願意承擔所移植板的後續更新工作,可以考慮加入維護人員(MAINTAINERS)開發隊伍行列。
在實際的U-Boot移植中,無法避免地會遇到一些難以預料的問題, 甚至出現倒退, 尤其是U-Boot移植新手,更會平添諸多難度。但筆者相信, 在逐步熟悉U-BOOt的移植方法和過程中,隨著自身經驗的不斷積累,加之有眾多熱衷於開放源碼人士的鼎立相助,堅冰終會消融。
參考文獻
1 http://cvs.sourceforge.net/viewcvs.py/u-boot/u-boot/
2 http://www.denx.de/twiki/bin/view/DULG/Manual
3 Motorola.PowerPC MPC823 IJser,S Manual