初學嵌入式Linux,感覺需要學習的東西太多了。把學習過程中的收獲和問題記錄在這裡,算是一份經驗吧。
前面利用開發闆帶的現成的東西step by step讓Linux 2.4.19在開發闆上跑起來了,對于開發的流程也有了一定的認識。現在想對每一步進行詳細深入的探讨,好好學習一下,把筆記記錄下來,省得忘記了。有些内容是從看過的書中摘要過來的,大部分是自己實踐後的心得。我想記得詳細點,也好為後面總結打好基礎。
先談一下對于嵌入式開發流程和嵌入式開發環境拓撲結構的認識。
剛開始比較盲目,看得書也不多,現在才算是大體上有了些了解。從開發産品的角度簡單的描述如下:
一、嵌入式開發流程簡介
假設我們現在進行一項嵌入式開産品的開發,比如說智能電力系統終端,那麼我想首先應該對完整的開發流程有一個大緻的了解,才不緻于在以後的工作中被動。下面對嵌入式linux開發簡單的介紹一下。
1、系統的需求分析
2、硬體平台的選擇和設計
3、軟體開發
(3-1)建立開發環境。
(3-2)引導裝載程式。
(3-3)核心裁減與編譯。
(3-4)建立檔案系統。
(3-5)應用程式開發。
圖1
因為我想要做的是軟體開發,是以對前兩步就不作深入探索了。隻想要對軟體開發的每一步熟悉起來,讓我定制的系統跑得穩定,開發的程式能很好的完成其功能。這是個很艱巨的任務,萬裡長征剛剛走了第一步:)
二、嵌入式開發環境拓撲結構簡介
嵌入式開發環境一般由:主控端(Linux Server)、工作站、嵌入式目标系統(target board)和将它們連在一起的網絡環境。
1、linux server:嵌入式linux核心編譯、應用程式編譯的公共平台,有單獨的一台pc機充當,安裝标準的linux作業系統,比如redhat,debian等等。
2、工作站:為普通區域網路計算機,以支援小組項目開發。工作站一般安裝windows,需要linux伺服器時,可以從工作站遠端登陸到linux server。
3、target board:這是需要開發的最終産品,可以根據需要與工作站連接配接(通常通過序列槽或者usb接口),或連至區域網路。
4、工作站需要安裝ftp用戶端(cuteftp、flashfxp等)和telnet用戶端程式(secureCRT等),linux伺服器應該開通ftp和telnet服務,還有ssh。
綜述過程:開發人員在一台工作站進行操作,通過遠端登陸的方式操作linux server,并且使用ftp在linux server和工作站進行檔案傳輸,同時target board需要與網絡連接配接,其序列槽與工作站的RS232接口連接配接。使用工作站上的超級終端作為嵌入式目标系統輸入/輸出端。
對于開發流程有了一定的了解後就有了目标,這樣才能夠不是太郁悶。
我的開發環境:Windows XP SP2+VMWARE+RedHat 9.0
首先規劃一下,我先建立了一個使用者armlinux,我的全部工作都是在這個使用者根目錄下完成。
$pwd
/home/armlinux
$mkdir bootloader debug images software source kernel rootfiles sysapps tmp tools program
$ls
bootloader images program software sysapps tools
debug kernel rootfiles source tmp
然後建立環境變量,直接在.bash_profile中改就可以了。
# .bash_profile
# Get the aliases and functions
if [ -f ~/.bashrc ]; then
. ~/.bashrc
fi
# User specific environment and startup programs
export TARGET=arm-linux
export PRJROOT=/home/armlinux
export PREFIX=${PRJROOT}/tools
export TARGET_PREFIX=${PREFIX}/${TARGET}
export PATH=$PATH:$HOME/bin:$PREFIX/bin:/sbin:/usr/sbin:/usr/local/sbin
unset USERNAME
這樣在下一次進入此使用者時,環境變量就生效了。如果想立刻生效,那麼可以用下面的指令:$source .bash_profile。這種方法可以使這些環境變量在進入使用者armlinux後就會成效,比較友善。
三、建立交叉編譯環境
這一步工作我已經很順利的完成了。剛開始時,手動建立交叉編譯工具鍊,很困難,出現了很多問題,幸虧網上有不少的資料可以參考。關于手動建立交叉編譯工具鍊的過程我已經做了總結,放到blog上了。現在可以獲得已經編譯好的工具鍊,這樣比較友善些,畢竟幾個小時的手動建立過程太繁瑣,太容易出錯了。
3.1 擷取交叉編譯工具鍊
網站:http://www.arm.linux.org.uk
在linux server上以ftp方式登陸:
#ftp ftp.arm.linux.org.uk
這是系統提示輸入使用者名和密碼,不要随便輸,那樣可能會連接配接失敗。該ftp站點是允許匿名通路的,是以你可以用下面的使用者名:anonymous登陸,密碼無,直接回車就可以了。
進入後執行:
ftp>cd pub/armlinux/toolchain/
ftp>bin
ftp>get cross-2.95.3.tar.bz2
ftp>get cross-3.0.tar.bz2
ftp>get cross-3.2.tar.bz2
ftp>get README
ftp>bye
Linux 2.4.xx及其以下的核心源碼用2.95.3的交叉編譯器來編譯就可以了;而2.6.xx的核心源碼一般要用到cross-3.x以上的版本來編譯。是以我全都下載下傳下來了,備用。若下載速度慢,可選擇在windows下用迅雷下載,速度很快。
要想用更新的版本,則可以到網站ftp://ftp.handhelds.org/projects/toolchain下載下傳,這裡可以下在到cross-3.3.2和cross-3.4.1,預設路徑是/usr/local/arm/<版本号>。
從手動編譯就可以知道,根據環境變量PREFIX指定了安裝目标檔案夾,那麼上面提供的編譯好的工具鍊也必須安裝到指定的檔案夾才可以使用。可以在README中知道安裝方法:
This works for both gcc-2.95.3 and gcc-3.0.
How to install:
cd /usr/local
mkdir arm
cd arm
tar Ixvf cross-.tar.bz2
Add /usr/local/arm//bin to your path to use the cross compiler.
在Linux下面要養成看README、INSTALL檔案的習慣,雖然是英文,但是寫得都比較具體,比較簡潔,沒有很困難的。
明确了方法就比較簡單了。
#mkdir /usr/local/arm
#cd /usr/local/arm
#tar jxvf cross-2.95.3.tar.bz2
然後添加路徑:
$cd
$ls -a
$vi .bash_profile
# .bash_profile
# Get the aliases and functions
if [ -f ~/.bashrc ]; then
. ~/.bashrc
fi
# User specific environment and startup programs
export TARGET=arm-linux
export PRJROOT=/home/armlinux
export PREFIX=${PRJROOT}/tools
export TARGET_PREFIX=${PREFIX}/${TARGET}
export PATH=$PATH:$HOME/bin:$PREFIX/bin:/usr/local/arm/2.95.3/bin:/sbin:/usr/sbin:/usr/local/sbin
unset USERNAME
修改好後,終端執行指令:
$. .bash_profile //讓配置檔案生效
看見紅色的行就是修改好的。隻需要把你的路徑添加到後面就可以了。
這樣可以驗證一下了。
驗證:
$cd
$cd program
$vi hello.c
-------------------------------------------
#include
int main()
{
int i;
for(i=1;i<9;i++)
printf("Hello World %d times!\n",i);
}
--------------------------------------------
儲存後退出。
$arm-linux-gcc hello.c -o hello-arm
$file hello-arm
hello-arm: ELF 32-bit LSB executable, ARM, version 1 (ARM), for GNU/Linux 2.0.0, dynamically linked (uses shared libs), not stripped
這就說明生成的hello-arm是可以工作在ARM平台上的,也證明了你的交叉編譯工具鍊是有效并且可用的。
在下載下傳的2.95.3的工具鍊中沒有包含調試工具gdb和目标闆的gdbserver。在這裡一起搭建好。
首先從ftp://ftp.gnu.org/gnu/gdb中獲得gdb套件。解壓縮關于路徑就不多說了。
$cd
$cd debug
$mkdir build-gdb build-gdbserver
$cd
$cd software
$../source/gdb-5.2.1/configure --target=$TARGET --prefix=$PREFIX
$make
$make install
這樣就可以順利的完成gdb-5.2.1的安裝了。
要想對目标闆進行交叉編譯,gdb顯得太大了些,是以需要gdbserver。下面建立gdbserver。
$cd
$cd debug/build-gdbserver
$chmod +x ../../source/gdb-5.2.1/gdb/gdbserver/configure
$CC=arm-linux-gcc ../../source/gdb-5.2.1/gdb/gdbserver/configure --host=$TARGET --prefix=$TARGET_PREFIX
$make
$make install
n=`echo gdbserver | sed 's,x,x,'`; \
if [ x$n = x ]; then n=gdbserver; else true; fi; \
/usr/bin/install -c gdbserver /home/armlinux/tools/arm-linux/bin/$n; \
/usr/bin/install -c -m 644 ../../software/gdb-5.2.1/gdb/gdbserver/gdbserver.1 /home/armlinux/tools/arm-linux/man/man1/$n.1
/usr/bin/install: 無法建立一般檔案‘/home/armlinux/tools/arm-linux/bin/gdbserver’: 沒有那個檔案或目錄
/usr/bin/install: 無法建立一般檔案‘/home/armlinux/tools/arm-linux/man/man1/gdbserver.1’: 沒有那個檔案或目錄
make: *** [install-only] Error 1
此處錯誤不難了解,主要是因為交叉編譯工具放到/usr/local/arm裡面了。前面的安裝目錄tools裡面缺少幾個檔案夾,隻需要建立就可以了。
$cd $PRJROOT/tools
$mkdir arm-linux
$cd arm-linux
$mkdir bin man
$cd man
$mkdir man1
$cd $PRJROOT/debug/build-gdbserver
$make install
這樣就沒有問題了,當然也可以修改makefile,但是自己還沒有學好shell語言,是以采取上述方法解決了。這樣首先用strip處理一下,目的是gdbserver不需要附帶上調試的資訊,把它們都剝離去就是了。
$arm-linux-strip $TARGET_PREFIX/bin/gdbserver/gdbserver
$ls -l $TARGET_PREFIX/bin/
總用量 24
-rwxr-xr-x 1 armlinux armlinux 23132 8月 10 11:33 gdbserver
也就是說,gdbserver經過strip處理之後還剩下23KB多一點,已經挺小了,适合目标闆了。
附:
在CU論壇上看到tree工具可以檢視目錄樹,覺得不錯。也想要安裝一個。下面這個站點已經沒有tree-1.5.0.tgz。
有效的下載位址:http://linus.yhspatriot.net/cs/cs/assignments/q1/introToUnix.html
$cd
$cd source
$ftp mama.indstate.edu
Connected to mama.indstate.edu (139.102.70.201).
220 ProFTPD 1.3.0 Server (ProFTPD Default Installation) [139.102.70.201]
Name (mama.indstate.edu:armlinux): anonymous
331 Anonymous login ok, send your complete email address as your password.
Password:
230 Anonymous access granted, restrictions apply.
Remote system type is UNIX.
Using binary mode to transfer files.
ftp> cd linux/tree
250 CWD command successful
ftp> ls
227 Entering Passive Mode (139,102,70,201,149,53).
150 Opening ASCII mode data connection for file list
drwxr-xr-x 2 root root 4096 Jun 4 2001 binary
drwxr-xr-x 2 root root 4096 May 19 1999 slack
-rw-r--r-- 1 root root 406 Oct 11 1996 tree-1.1.lsm
-rw-r--r-- 1 root root 13135 Oct 11 1996 tree-1.1.tgz
-rw-r--r-- 1 root root 405 Jan 6 1997 tree-1.2.lsm
-rw-r--r-- 1 root root 16362 Jan 6 1997 tree-1.2.tgz
-rw-r--r-- 1 root root 436 Feb 21 2002 tree-1.3.lsm
-rw-r--r-- 1 root root 25060 Feb 21 2002 tree-1.3.tgz
-rw-r--r-- 1 root root 432 Feb 21 2002 tree-1.4b1.lsm
-rw-r--r-- 1 root root 27536 Feb 21 2002 tree-1.4b1.tgz
-rw-r--r-- 1 root root 27891 Mar 25 2002 tree-1.4b2.tgz
-rw-r--r-- 1 root root 432 Jun 18 2003 tree-1.4b3.lsm
-rw-r--r-- 1 root root 29366 Feb 6 2003 tree-1.4b3.tgz
-rw-r--r-- 1 root root 466 Aug 20 2004 tree-1.5.0.lsm
-rw-r--r-- 1 root root 26543 Aug 16 2004 tree-1.5.0.tgz
226 Transfer complete.
ftp> get tree-1.5.0.tgz
ftp> bye
221 Goodbye.
在Windows下解壓tree-1.5.0.tgz,將解壓後的檔案夾tree-1.5.0拷到/home/zhj1011/software下。
$cd /home/zhj1011/software/tree-1.5.0
$make
$make install
然後就可以了,安裝路徑檢視makefile檔案知道在/usr/local/bin,也可以用which檢視。現在可以用tree指令來檢視一下自己的目錄結構了。
示例:
$cd
$tree -L 1 //顯示一級目錄,當然也可以顯示二級目錄了。
.
|-- bootloader
|-- debug
|-- images
|-- kernel
|-- program
|-- rootfiles
|-- software
|-- source
|-- sysapps
|-- tmp
`-- tools
這樣對自己的組織比較好。等用tree熟悉了,在補充它的用法。
四、引導裝載程式bootloader
因為u-boot的功能比較強大,是以選擇了u-boot。這幾天想先研究研究它的代碼,好好分析一下啟動過程。原來做過一次,不過是利用原來開發闆做好的,熟悉過程是可以,但是不明白原理仍然不行。這次要學習掌握原理部分。
待續。。。。
2006-08-14
一、了解一下存儲器的基本分類情況。
存儲器的實體實質是一組或多組具備資料輸入輸出和資料存儲功能的內建電路,用于充當裝置緩存或儲存固定的程式及資料。存儲器按存儲資訊的功能可分為隻讀存儲器ROM(Read Only Memory)和随機存儲器RAM(Random Access Memory)。
圖1 常見存儲器分類
1、 ROM
ROM 中的資訊一次寫入後隻能被讀出,而不能被操作者修改或删除,一般由晶片制造商進行掩膜寫入資訊,價格便宜,适合于大量的應用。一般用于存放固定的程式,如監控程式、彙程式設計式等,以及存放各種表格。EPROM(Erasable Programmable ROM)和一般的ROM不同點在于它可以用特殊的裝置擦除和重寫它的内容,一般用于軟體的開發過程。
特别介紹:閃存(Flash Memory)
閃速存儲器(Flash Memory)又稱PEROM(Programmable and Erasable Read Only Memory),是Intel 公司在80 年代末90 年代初推出的,由于它的衆多優點而深受使用者的青睐。Flash Memory 的兩個主要特點是可以按整體/扇區擦除和按位元組程式設計。它是完全非易失的,可以線上寫入,并且可以按頁連續位元組寫入,讀出速度高。Flash 晶片劃分成很多扇區,把一位從0 重置為1 不能通過對該位單獨操作來實作,而必須擦除整個扇區。Flash晶片的壽命就用擦除周期來衡量。通常的壽命為每個扇區可擦除100,000 次。為了避免任意一個扇區在其他扇區之前達到這個極限,大多數Flash 晶片使用者會盡量保證擦除次數在各扇區之間均勻分布,這一過程稱為“磨損均衡”(wear leveling)
2、 RAM
RAM 就是我們平常所說的記憶體,主要用來存放各種現場的輸入、輸出資料,中間計算結果,以及與外部存儲器交換資訊和作堆棧用。它的存儲單元根據具體需要可以讀出,也可以寫入或改寫。RAM 隻能用于暫時存放程式和資料,一旦關閉電源或發生斷電,其中的資料就會丢失。現在的RAM 多為MOS 型半導體電路,它分為靜态和動态兩種。靜态RAM 是靠雙穩态觸發器來記憶資訊的;動态RAM 是靠MOS 電路中的栅極電容來記憶資訊的。由于電容上的電荷會洩漏,需要定時給與補充,是以動态RAM 需要設定重新整理電路。但動态RAM 比靜态RAM 內建度高、功耗低,進而成本也低,适于作大容量存儲器。是以主記憶體通常采用動态RAM,而高速緩沖存儲器(Cache)則使用靜态RAM。動态RAM 按制造技術的不同,又可分為動态随機存儲器(Dynamic RAM)、擴充資料輸出随機存儲器(Extended Data Out RAM)和同步動态随機存儲器(Synchromized DynamicRAM)。DRAM 需要恒電流以儲存資訊,一旦斷電,資訊即丢失。它的重新整理頻率每秒鐘可達幾百次,但由于DRAM 使用同一電路來存取資料,是以DRAM 的存取時間有一定的時間間隔,這導緻了它的存取速度并不是很快。另外,在DRAM 中,由于存儲位址空間是按頁排列的,是以當通路某一頁面時,切換到另一頁面會占用CPU 額外的時鐘周期。EDO-RAM同DRAM 相似,但在把資料發送給CPU 的同時可以去通路下一個頁面,故而速度要比普通DRAM 快15~30%。SDRAM同DRAM 有很大差別,它使用同一個CPU 時鐘周期即可完成資料的通路和重新整理,即以同一個周期、相同的速度、同步的工作,因而可以同系統總線以同頻率工作,可大大提高資料傳輸率,其速度要比DRAM 和EDO-RAM 快很多(比EDO-RAM提高近50%)。
二、AT91RM9200開發闆的存儲器情況
第一級位址譯碼由存儲控制器執行,即由具有附加功能的進階系統總線(ASB) 執行。譯碼将4G的位址空間分為16 個256M位元組的區域。區域1 ~ 8對應EBI,和外部片選NC0 ~NCS7相聯系。區域0為内部存儲器位址,第二級譯碼提供1M位元組内部存儲空間。區域15為外設位址,且提供對進階外設總線(APB) 的通路。其它區域未使用,使用它們進行通路時将向發出通路請求的主機發出異常中斷。注意,位址的轉換都是按照位元組為機關的。
1、内部存儲器映射
内部ROM:AT91RM9200內建了一個128-K位元組的内部ROM。任何時候,ROM均被映射到位址0x10 0000。若複位時BMS(引導模式選擇引腳) 為高,則在複位後到重新映射指令執行前,可通路位址0x0。ROM容量為128KB,即對應0x20000。是以範圍為0x100000-0x120000。
内部RAM:AT91RM9200內建了高速,16-K 位元組的内部SRAM。複位後到重新映射指令執行前,隻可通路SRAM 中0x20 0000的位址空間。重新映射後, SRAM 在位址0x0 同樣有效。SRAM容量為16KB,即對應0x4000,是以範圍為0x200000-0x204000。
USB 主機端口:AT91RM9200內建了一個USB主機端口開放主機控制器接口(OHCI)。ASB可直接通路該接口寄存器,且同标準内部存儲器一樣映射到位址0x30 0000。
圖2 内部存儲器映射
2、外部存儲器映射
圖3 外部存儲器映射
嵌入式儲存設備通常主要是RAM 和作為永久存儲媒質的Flash。
現在所用的AT91RM9200開發闆所用的SDRAM是HY57V281620HCT-H,其容量為4banks×2Mbits×16,即128Mbits=16Mbytes。SDRAM共有兩片HY57V281620HCT-H,是以SDRAM容量為32MB。
現在所用的Flash晶片為Intel的28F640J3,容量為8MB,位址映射從0x10000000到0x10800000。現在将Flash分為64個扇區,每個扇區為128KB=0x20000,每個扇區分為兩個擦除塊,為64KB=0x10000。
-------------------------------------------------------------------
Chip Select 0――Flash(0x1000 0000-0x1FFF FFFF)
0x1000 0000(第0扇區)
boot.bin Flash
0x1001 0000(第0扇區)
u-boot.bin.gz Flash
0x1002 0000(第1扇區)
uImage Flash
.
.
.
0x1012 0000(第9扇區)
ramdisk Flash
.
.
.
0x107E 0000(第63扇區)
u-boot環境變量 Flash
-------------------------------------------------------------------
Chip Select 1――SDRAM(0x2000 0000-0x2200 0000)
0x2000 0000
SDRAM
.
.
0x2100 0000
uImage SDRAM
0x2110 0000
ramdisk SDRAM
.
.
-------------------------------------------------------------------
2006-08-17 u-boot移植
1 首先,了解一下bootloader。bootloader是系統加電後運作的第一段代碼。它要完成的工作就是初始化硬體裝置,建立記憶體空間的映射圖,這樣為最終調用作業系統核心做好準備。
2 bootloader的操作模式
(1)啟動加載模式(bootloading)
(2)下載下傳模式(downloading)
開發時要用(2),target board上的bootloader将通過序列槽或者網絡等通信手段從host上下載下傳核心映象和根檔案系統映象等到ram中。
3 bootloader的啟動方式:網絡啟動、磁盤啟動、flash啟動。
4 bootloader的種類
區分一下“bootloader”和“monitor”的概念。bootloader隻是引導裝置并且執行主程式的固件;而monitor還提供了更多的指令行接口,可以進行調試、讀寫記憶體、燒寫flash、配置環境變量等。monitor在嵌入式系統開發過程中還可以提供很好的調試功能,開發完成後,就完全配置成了一個bootloader。是以,習慣上把它們統稱為bootloader。我現在要使用的u- boot就是典型的monitor。
5 bootloader的啟動流程
搜集了一些資料,寫的比較精彩,放在這裡。。。
資料一:
系統上電,檢測BMS(引導模式選擇引腳),選擇系統的啟動方式,如果BMS(引導模式選擇引腳)為高電平,則系統從片内ROM啟動。AT91RM9200的ROM上電後被映射到了0x0和0x100000處,在這兩個位址處都可以通路到ROM。由于9200的ROM中固化了一個BOOTLOAER程式。是以PC從0X0處開始執行這個BOOTLOAER(準确的說應該是一級BOOTLOADER)。這個BOOTLOER 依次完成以下步驟:
1. PLL SETUP //PLL:鎖相環,倍頻的作用。
設定PLLB産生48M時鐘頻率提供給USB DEVICE。同時DEBUG USART也被初始化為48M的時鐘頻率。
2. 相應模式下的堆棧設定
3. 檢測主時鐘源(Main oscillator)
4. 中斷控制器(AIC)的設定
5. C 變量的初始化
6. 跳到主函數
完成以上步驟後,我們可以認為BOOT過程結束,接下來的就是LOADER的過程,或者也可以認為是裝載二級BOOTLOER。AT91RM9200按照DATAFLASH、EEPROM、連接配接在外部總線上的8位并行FLASH的順序依次來找合法的BOOT程式。所謂合法的指的是在這些儲存設備的開始位址處連續的存放的32個位元組,也就是8條指令必須是跳轉指令或者裝載PC的指令,其實這樣規定就是把這8條指令當作是異常向量表來處理。必須注意的是第6 條指令要包含将要裝載的映像的大小。關于如何計算和寫這條指令可以參考使用者手冊。一旦合法的映像找到之後,則BOOT程式會把找到的映像搬到SRAM中去,是以映像的大小是非常有限的,不能超過16K的大小。當BOOT程式完成了把合法的映像搬到SRAM的任務以後,接下來就進行存儲器的REMAP,經過REMAP之後,SRAM從映設前的0X200000位址處被映設到了0X0位址并且程式從0X0處開始執行。而ROM這時隻能在0X100000這個位址處看到了。至此9200就算完成了一種形式的啟動過程。如果BOOT程式在以上所列的幾種儲存設備中找到合法的映像,則自動初始化DEBUG USART口和USB DEVICE口以準備從外部載入映像。對DEBUG口的初始化包括設定參數115200 8 N 1以及運作XMODEM協定。對USB DEVICE進行初始化以及運作DFU協定。現在使用者可以從外部(假定為PC平台)載入你的映像了。在PC平台下,以WIN2000為例,你可以用超級終端來完成這個功能,但是還是要注意你的映像的大小不能超過13K。一旦正确從外部裝載了映像,接下來的過程就是和前面一樣重映設然後執行映像了。我們上面講了BMS(引導模式選擇引腳)為高電平,AT91RM9200選擇從片内的ROM啟動的一個過程。如果BMS(引導模式選擇引腳)為低電平,則AT91RM9200會從片外的FLASH啟動,這時片外的FLASH的起始位址就是0X0了,接下來的過程和片内啟動的過程是一樣的,隻不過這時就需要自己寫啟動代碼了,至于怎麼寫,大緻的内容和ROM的BOOT差不多,不同的硬體設計可能有不一樣的地方,但基本的都是一樣的。由于片外FLASH可以設計的大,是以這裡編寫的 BOOTLOADER可以一步到位,也就是說不用像片内啟動可能需要BOOT好幾級了,目前AT91RM9200上使用較多的bootloer是u-boot,這是一個開放源代碼的軟體,使用者可以***下載下傳并根據自己的應用配置。
資料2
loader.bin, boot.bin, u-boot.bin代碼執行流分析.
以上三個檔案時at91rm9200啟動所需要的三個bin,他們的實作代碼并不難。
如果是你是采用at91rm9200的評估版,應該能得到其源碼。
loader.bin 執行流程,這個檔案主要在片内啟動從序列槽下載下傳代碼時會用到
loader/entry.S init cpu
b main ---> crt0.S
--> copydata --> clearbss --> b boot
main.c --> boot -->
/*Get internel rom service address*/
/* Init of ROM services structure */
pAT91 = AT91C_ROM_BOOT_ADDRESS;
/* Xmodem Initialization */
--> pAT91->OpenSBuffer
--> pAT91->OpenSvcXmodem
/* System Timer initialization */
---> AT91F_AIC_ConfigureIt
/* Enable ST interrupt */
AT91F_AIC_EnableIt
AT91F_DBGU_Printk("XMODEM: Download U-BOOT ");
Jump.S
// Jump to Uboot BaseAddr exec
Jump((unsigned int)AT91C_UBOOT_BASE_ADDRESS)
boot.bin執行流程 該檔案會在從片内啟動時被下載下傳到闆子上,以後還會被燒寫到片外Flash中,以便在片外啟動時
用它來引導并解壓u-boot.bin.gz,并跳轉到u-boot來執行。
boot/entry.S
b main --> crt0.S --> copydata --> clearbss --> b boot
AT91F_DBGU_Printk(" ");
AT91F_DBGU_Printk("************************************** ");
AT91F_DBGU_Printk("** Welcome to at91rm9200 ** ");
AT91F_DBGU_Printk("************************************** ");
boot/misc.s /* unzip uboot.bin.gz */
----> decompress_image(SRC,DST,LEN) --> gunzip
//jump to ubootBaseAddr exec 這裡跳轉到解壓u-boot.bin.gz的位址處直接開始執行u-boot
asm("mov pc,%0" : : "r" (DST));
u-boot.bin執行流程
u-boot/cpu/at91rm9200/start.S
start --->reset
---> copyex ---> cpu_init_crit
---> /* set up the stack */ --> start_armboot
u-boot/lib_arm/board.c
init_fnc_t *init_sequence[] = {
cpu_init, /* basic cpu dependent setup */
board_init, /* basic board dependent setup */
interrupt_init, /* set up exceptions */
env_init, /* initialize environment */
init_baudrate, /* initialze baudrate settings */
serial_init, /* serial communications setup */
console_init_f, /* stage 1 init of console */
display_banner, /* say that we are here */
dram_init, /* configure available RAM banks */
display_dram_config,
checkboard,
NULL,
};
---> start_armboot ---> call init_sequence
---> flash_init --> display_flash_config
---> nand_init ---> AT91F_DataflashInit
---> dataflash_print_info --> env_relocate
---> drv_vfd_init --> devices_init --> jumptable_init
---> console_init_r --> misc_init_r --> enable_interrupts
---> cs8900_get_enetaddr --> board_post_init -->
u-boot/common/main.c
for (;;)
{ /* shell parser */
main_loop () --> u_boot_hush_start --> readline
--> abortboot
-->printf("Hit any key to stop autoboot: %2d ", bootdelay);
}
以上是at91rm9200啟動并進入u-boot的執行流分析。後面u-boot還會将uImage解壓到特定的位置并開始執行核心代碼。
6 u-boot-1.1.1的移植
自己先用u-boot-1.1.1,主要步驟如下:
(1)下載下傳u-boot-1.1.1
http://sourceforge.net/projects/u-boot
(2)解壓
使用者:armlinux
$mkdir bootloader
$cd bootloader
$tar jxvf ../source/u-boot-1.1.1.tar.bz2
$cd u-boot-1.1.1
(3)修改
首先看一下結構
$ tree -L 1 -d
.
|-- board 平台依賴,存放電路闆相關的目錄檔案
|-- common 通用多功能函數的實作
|-- cpu 平台依賴,存放cpu相關的目錄檔案
|-- disk 通用。硬碟接口程式
|-- doc 文檔
|-- drivers 通用的裝置驅動程式,如以太網接口驅動
|-- dtt
|-- examples 應用例子
|-- fs 通用存放檔案系統的程式
|-- include 頭檔案和開發闆配置檔案,所有開發闆配置檔案放在其configs裡
|-- lib_arm 平台依賴,存放arm架構通用檔案
|-- lib_generic 通用的庫函數
|-- lib_i386 平台依賴,存放x86架構通用檔案
|-- lib_m68k 平台依賴
|-- lib_microblaze 平台依賴
|-- lib_mips 平台依賴
|-- lib_nios 平台依賴
|-- lib_ppc平台依賴,存放ppc架構通用檔案
|-- net 存放網絡的程式
|-- post 存放上電自檢程式
|-- rtc rtc的驅動程式
`-- tools 工具
然後具體步驟為:
(一)在board檔案夾下面建立自己的開發闆的檔案夾。一般的,要選取與自己的開發闆硬體設定最為接近的型号。在u-boot-1.1.1中,已經支援at91rm9200,是以可以選取at91rm9200dk作為模闆進行修改。設定你的開發闆的名字,随意即可,我的設定為:myboard。
[armlinux@lqm u-boot-1.1.1]$ cd board
[armlinux@lqm board]$ cp -R at91rm9200dk/ myboard/
[armlinux@lqm board]$ cd myboard
[armlinux@lqm myboard]$ ls
at91rm9200dk.c config.mk flash.c Makefile u-boot.lds
(二)可以看到,這裡共有5個檔案。首先,要修改主檔案的名字,即要把at91rm9200dk.c更改為 myboard.c。其次,要更改config.mk中TEXT_BASE的數值,與loader等一級bootloader的要一緻。接下來,因為在 at91rm9200dk用的是AMD的flash,而我的開發闆上用的是Intel的28F640J3,那麼需要另外找Intel的flash.C,以減少工作量。在這裡,推薦用source insight這個檢視代碼的工具。我是在win下面使用的,它可以很友善的讀代碼,并且查找調用函數等等的工作。在strong ARM構架裡有xm250,它的flash是Intel的,修改的東西并不是很多。需要注意的是,xm250的flash位寬是32,而我的位寬是16,要根據這個進行相應的修改。最後,修改Makefile,主要是修改生成檔案的名字。具體操作如下:
[armlinux@lqm myboard]$ mv at91rm9200dk.c myboard.c
[armlinux@lqm myboard]$ cat config.mk
TEXT_BASE = 0x21f80000
[armlinux@lqm myboard]$ vi config.mk
修改成:TEXT_BASE = 0x21f00000,然後儲存退出。
[armlinux@lqm myboard]$ vi Makefile
include $(TOPDIR)/config.mk
LIB = lib$(BOARD).a
OBJS := myboard.o flash.o
SOBJS :=
$(LIB): $(OBJS) $(SOBJS)
$(AR) crv $@ $(OBJS) $(SOBJS)
clean:
rm -f $(SOBJS) $(OBJS)
[armlinux@lqm myboard]$ rm flash.c
[armlinux@lqm myboard]$ cp ../xm250/flash.c ./
[armlinux@lqm myboard]$ ls
config.mk flash.c Makefile myboard.c u-boot.lds
[armlinux@lqm myboard]$ vi flash.c
34 #undef FLASH_PORT_WIDTH32 /*不定義位寬32*/
35 #define FLASH_PORT_WIDTH16 /*定義位寬16*/
216 switch (value) {
217
218 case (FPW) INTEL_ID_28F128J3A:
219 info->flash_id += FLASH_28F128J3A;
220 info->sector_count = 128;
221 info->size = 0x01000000;
222 break; /* => 16 MB */
223
224 case (FPW) INTEL_ID_28F640J3A: /*就是這個晶片*/
225 info->flash_id += FLASH_28F640J3A;
226 info->sector_count = 64;
227 info->size = 0x00800000;
228 break; /* => 8 MB */
[armlinux@lqm myboard]$ cd ../..
[armlinux@lqm u-boot-1.1.1]$ vi Makefile
#########################################################################
## AT91RM9200 Systems
#########################################################################
at91rm9200dk_config : unconfig
@./mkconfig $(@:_config=) arm at91rm9200 at91rm9200dk
myboard_config : unconfig
@./mkconfig $(@:_config=) arm at91rm9200 myboard
#########################################################################
在這裡,可以在指令模式下輸入“/at91rm9200”快速查找 at91rm9200dk,仿照它的例子,寫出自己闆子的配置。注意的是,第二行開頭要用TAB鍵,不是空格,否則報錯。選項arm表示目标闆架構, at91rm9200表是片上系統,myboard是你自己的開發闆名字。
[armlinux@lqm u-boot-1.1.1]$ vi MAKEALL
LIST_ARM9=" \
at91rm9200dk integratorcp integratorap \
omap1510inn omap1610h2 omap1610inn \
smdk2400 smdk2410 trab \
VCMA9 versatile myboard \
"
(三)修改主要的配置檔案。配置選項比較多,主要是配置cpu,波特率,flash和sdram的類型大小,環境變量的偏移量等等,容易出錯。應該首先了解硬體情況,仔細對應晶片資料進行修改。
[armlinux@lqm u-boot-1.1.1]$ cd include/configs
[armlinux@lqm configs]$ cp at91rm9200dk.h myboard.h
[armlinux@lqm configs]$ vi myboard.h
//行號和實際的myboard.h的行號有所偏差,認真修改好配置就可以了。
41 #define CONFIG_MYBOARD 1 目标闆
65 #define CONFIG_BOOTDELAY 5 u-boot延時等待時間
110 #define CONFIG_NR_DRAM_BANKS 1 sdram banks,我的是一個
111 #define PHYS_SDRAM 0x20000000 sdram起始位址
112 #define PHYS_SDRAM_SIZE 0x2000000 sdram容量32MB
121 #undef CONFIG_HAS_DATAFLASH 未用dataflash
128 #define PHYS_FLASH_1 0x10000000
129 #define PHYS_FLASH_2 0x00000000 定義,flash.c用到,但實際并未起作用
130 #define PHYS_FLASH_SIZE 0x800000 flash容量8MB
131 #define CFG_FLASH_BASE PHYS_FLASH_1 flash起始位址别名
132 #define CFG_MAX_FLASH_BANKS 1 flash最大banks數
133 #define CFG_MAX_FLASH_SECT 64 扇區總數
134 #define PHYS_FLASH_SECT_SIZE (128*1024) 每個扇區128KB
135 #define CFG_FLASH_ERASE_TOUT (2*CFG_HZ) /* Timeout for Flash Erase */
136 #define CFG_FLASH_WRITE_TOUT (2*CFG_HZ) /* Timeout for Flash Write */
137 #define CFG_FLASH_UNLOCK_TOUT (2*CFG_HZ)
138
139 #undef CFG_ENV_IS_IN_DATAFLASH
140
141 #ifdef CFG_ENV_IS_IN_DATAFLASH
142 #define CFG_ENV_OFFSET 0x20000
143 #define CFG_ENV_ADDR (CFG_DATAFLASH_LOGIC_ADDR_CS0 + CFG_ENV_OFFSET)
144 #define CFG_ENV_SIZE 0x2000 /* 0x8000 */
145 #else
146 #define CFG_ENV_IS_IN_FLASH 1
147 #define CFG_ENV_ADDR (PHYS_FLASH_1 + 0x7e0000) /* 0x107E0000 */
148 #define CFG_ENV_SIZE 0x20000 環境變量占了一個扇區,共128KB
149 #endif
150
151 #define CFG_SOFT_RESET 1 定義軟複位,flash.c用到
152 #define CFG_LOAD_ADDR 0x21000000 /* default load address */
160 #define CFG_PROMPT "U-boot> " 提示符名字,可任意改
[armlinux@lqm configs]$ cd ../..
[armlinux@lqm u-boot-1.1.1]$ make myboard_config
Configuring for myboard board...
[armlinux@lqm u-boot-1.1.1]$ make CROSS_COMPILE=arm-linux-
然後把生成的u-boot.bin儲存,并且壓縮一下得到u-boot.bin.gz。将這兩個檔案通過ftp傳至windows上,通過SecureCRT來進行傳輸。
//u-boot.bin在目錄: u-boot-1.1.1下。
$gzip u-boot.bin //壓縮得到u-boot.bin.gz
這裡注意,知道CROSS_COMPILE路徑,前面設定環境變量時說到過。壓縮指令為gzip
利用交叉線将com1和開發闆序列槽相連。首先設定為片内啟動方式,上電。超級終端首先出現“CCCC”,這時利用modem協定傳輸loader.bin,成功後傳輸u-boot.bin。具展現象如下:
--------------------------------------------------------------
CCCCCCCCCCCC
正在開始 xmodem 傳輸。 按 Ctrl+C 取消。
正在傳輸 loader.bin...
100% 6 KB
-I- AT91F_LowLevelInit(): Debug channel initialized 6 KB/s 00:00:01 0 錯誤
loader 1.0 (Aug 8 2003 - 12:01:07)
XMODEM: Download U-BOOT
CCCCCCCCCCCCC
正在開始 xmodem 傳輸。 按 Ctrl+C 取消。
正在傳輸 u-boot.bin...
100% 85 KB 6 KB/s 00:00:14 0 錯誤
U-Boot downloaded successfully
U-Boot 1.1.1 (Aug 17 2006 - 14:07:56)
U-Boot code: 21F00000 -> 21F156CC BSS: -> 21F198D0
RAM Configuration:
Bank #0: 20000000 32 MB
Flash: 8 MB
*** Warning - bad CRC, using default environment
In: serial
Out: serial
Err: serial
U-boot> version
U-Boot 1.1.1 (Aug 17 2006 - 14:07:56)
U-boot> printenv
bootdelay=5
baudrate=115200
stdin=serial
stdout=serial
stderr=serial
Environment tes
-------------------------------------------------------
設定環境變量,當然這些也可以在include/configs/.h裡面定義。
U-boot> setenv ipaddr 192.168.1.100
U-boot> setenv serverip 192.168.1.106
U-boot> setenv ethaddr 36:B9:04:00:24:80
注意:實體位址應該合法,在tools檔案夾内有一個檔案gen_eth_addr.c,利用其生成可執行檔案則能夠獲得有效的mac位址。你可以先用gcc編譯,生成可執行檔案,然後執行,獲得合法的mac位址。
U-boot> saveenv
Saving Environment to Flash...
Un-Protected 1 sectors
Erasing Flash...
Erasing sector done
Erased 1 sectors
Writing to Flash...\done
Protected 1 sectors
U-boot> tftpboot 20000000 boot.bin
TFTP from server 192.168.1.106; our IP address is 192.168.1.100
Filename 'boot.bin'.
Load address: 0x20000000
Loading: ###
done
Bytes transferred = 10628 (2984 hex)
U-boot> protect off 1:0
Un-Protect Flash Sectors 0-0 in Bank # 1
U-boot> erase 1:0
Erase Flash Sectors 0-0 in Bank # 1
Erasing sector 0 ... done
U-boot> cp.b 20000000 10000000 2984
Copy to Flash...-done
U-boot> tftpboot 20000000 u-boot.bin.gz
TFTP from server 192.168.1.106; our IP address is 192.168.1.100
Filename 'u-boot.bin.gz'.
Load address: 0x20000000
Loading: #########
done
Bytes transferred = 43791 (ab0f hex)
U-boot> cp.b 20000000 10010000 ab0f
Copy to Flash...\done
斷電重新開機,從片外啟動。
這時遇到了一個問題,就是從flash啟動時,總是提示:*** Warning - bad CRC, using default environment,具體解決方法:
現象:配置好u-boot,在RAM裡正常啟動如下:
--------------------------------
U-Boot 1.1.2 (Aug 17 2006 - 14:07:56)
U-Boot code: 21F00000 -> 21F156CC BSS: -> 21F198D0
RAM Configuration:
Bank #0: 20000000 32 MB
Flash: 8 MB
*** Warning - bad CRC, using default environment
In: serial
Out: serial
Err: serial
U-boot>
--------------------------------
flash讀寫擦除均正常,當設定好環境變量,固化到flash之後,啟動仍然如上,即總是提示“*** Warning - bad CRC, using default environment”。使用md檢視環境變量所在63扇區,發現設定的環境變量仍然在。
問題解決:
通過分析u-boot的啟動流程,調試代碼,得知問題出在cpu/at91rm9200/start.S中。其中有一段代碼:
--------------------
ldr r0, =_start
ldr r1, =0x0
mov r2, #16
copyex:
subs r2, r2, #1
ldr r3, [r0], #4
str r3, [r1], #4
bne copyex
--------------------
它的作用是把中斷向量表從flash reload到RAM,以提高速度。但是它沒有進行remap。故而使得u-boot啟動之後無法尋找到環境變量所在的第63扇區。更改如下:
--------------------
if 0
ldr r0, =_start
ldr r1, =0x0
mov r2, #16
copyex:
subs r2, r2, #1
ldr r3, [r0], #4
str r3, [r1], #4
bne copyex
endif
--------------------
即把此段代碼注釋掉。
【或者是在此段前面加上remap部分,不過如果加上remap,則需要把前面的設定svc部分的代碼注釋掉,否則在u-boot>reset時會進入異常狀态。】
此解決方案對u-boot-1.1.2也有效。
U-Boot 1.1.1 (Aug 17 2006 - 16:50:31)
U-Boot code: 21F00000 -> 21F157F4 BSS: -> 21F199F4
RAM Configuration:
Bank #0: 20000000 32 MB
Flash: 8 MB
In: serial
Out: serial
Err: serial
U-Boot>
經驗證,這是u-boot-1.1.1已經能夠正常啟動了。
---------------------------
同樣的方法,u-boot-1.1.2也正常啟動了。另外,u-boot-1.1.2有幾個小的更新檔,等明天再做一下總結。同時看看如何制作更新檔,如何打更新檔。具體的調試過程沒有寫得很仔細,要想做好一項工作,隻會寫程式遠遠不夠,更為重要的是會調試。我需要加強此方面的工作。明天把JEDI probe調試環境的建立也總結一下。
2006-08-18
今天學習了一下Linux下面patch的制作和使用,做了總結,放到blog上面。u-boot-1.1.2有幾個diff更新檔檔案,具體沒有分析,先附在這裡。我的使用倒是還沒有發現這幾個問題,也許沒有測試,不管它,以後如果出現問題在來仔細考慮吧。
開發闆由王老師用,我先學習核心裁減吧。關于移植版本,不一定非得越高越好。關于核心版本标号問題,詳細參考《Building Embedded Linux Systems》。現在還不開發産品,那麼先多試用幾個,總結總結經驗。初步打算先移植一個2.4.x版本,然後移植一個2.6.x版本。
-----------------------------
Bug1:
RCS file: /home/cvs/u-boot/tools/env/fw_env.c,v
retrieving revision 1.2
diff -u -r1.2 fw_env.c
--- fw_env.c 21 Jul 2004 03:28:43 -0000 1.2
+++ fw_env.c 23 Jul 2004 05:00:25 -0000
@@ -612,8 +612,8 @@
if (!crc1_ok) {
fprintf (stderr,
"Warning: Bad CRC, using default environment\n");
- environment.data = default_environment;
- free (addr1);
+ memset(environment.data, 0, ENV_SIZE);
+ memcpy(environment.data, default_environment, sizeof(default_environment));
}
} else {
flag1 = environment.flags;
Bug2:
saveenv bad checksum
when saving environment after changing stdin,
stdout,... the checksum is not consistent.
Adding an env_crc_update() before saving environment
could solve this. i.e in common/cmd_nvedit.c in
function do_saveenv() :
int do_saveenv (cmd_tbl_t *cmdtp, int flag, int argc,char *argv[])
{
extern char * env_name_spec;
printf ("Saving Environment to %s...\n", env_name_spec);
env_crc_update();
----------------------------------------
2006-08-22
Linux核心移植
版本:Linux-2.4.27-vrs1
Target Board:ARM
U-boot:1.1.2
toolchain:cross-2.95.3
1、準備
kernel下載下傳到網站www.kernel.org,可以通過ftp方式:$ftp ftp.kernel.org,采用匿名的方式輸入anonymous即可進入下載下傳。
patch準備:到官方網站www.arm.linux.org.uk,這裡提供ftp方式$ftp ftp.arm.linux.org.uk
2、打好更新檔,執行make mrproper清理一下代碼樹。
3、修改根目錄的Makefile檔案,隻需修改ARCH和CROSS_COMPILE即可。
ARCH :=arm
CROSS_COMPILE=arm-linux-
在這裡,我已經将2.95.3放到PATH中,是以不需要寫全路徑。如果采用其他版本的toolchain,可以指明路徑,如:CROSS_COMPILE=/usr/local/arm/3.3.2/bin/arm-linux-
4、$make at91rm9200dk_config
該步的作用是把根目錄下面的.config重命名為.config.old,然後把arch/arm/defconfig/裡的at91rm9200dk開發闆的預設配置檔案複制到根目錄下,命名為.config。簡單的說,就是要利用提供的開發闆的配置檔案,然後在此基礎上進行修改。
下一步如果執行make oldconfig,那麼就完全按照.config來配置。而現在需要根據實際應用需要重新配置,是以不執行make oldconfig。而要執行make menuconfig。這兩個指令都是首先尋找預設的.config檔案并且執行,但不同的是,make oldconfig隻出現.config沒有的新配置選項供選擇。而make menuconfig則提供所有選項,圖形界面預設的是.config的配置。
在這裡,還是推薦在提供的開發闆配置檔案的基礎之上進行修改,否則後面很容易出現意想不到的問題。我就是因為開始沒有使用預設配置,後面的錯誤一個接一個,折騰了一個上午。
5、make menuconfig
在這裡可以重新配置,根據你所需要的功能進行裁減。
6、make clean dep
建立依賴關系。
7、make Image 或者 make zImage。這要看你後面使用什麼方式的核心映象。如果是make Image,則生成vmlinux,需要arm-linux-objcopy進行處理,生成uImage影響檔案。如果是make zImage,則生成zImage,vmlinux,system.map。
zImage和uImage對應的u-boot處理的方式也不相同,分别對應着go和bootm。
8、
[armlinux@lqm linux-2.4.27]$ cp arch/arm/boot/zImage /home/armlinux/images/zImage-2.4.27-vrs1
[armlinux@lqm linux-2.4.27]$ cp vmlinux $PRJROOT/images/vmlinux-2.4.27-vrs1
[armlinux@lqm linux-2.4.27]$ cp System.map $PRJROOT/images/System.map-2.4.27-vrs1
[armlinux@lqm linux-2.4.27]$ cp .config $PRJROOT/images/2.4.27-vrs1.config
9、生成uImage
[armlinux@lqm linux-2.4.27]$ arm-linux-objcopy -O binary -S vmlinux linux.bin
[armlinux@lqm linux-2.4.27]$ gzip -v9 linux.bin
linux.bin: 55.7% -- replaced with linux.bin.gz
[armlinux@lqm linux-2.4.27]$ ../../bootloader/u-boot-1.1.2/tools/mkimage -n 'RAM disk' -A arm -O linux -T kernel -C gzip -a 0x20008000 -e 0x20008000 -d linux.bin.gz uImage
//糾正:利用mkimage制作uImage,其中-T後跟type,此時應該為kernel,不應該為ramdisk。如果是ramdisk,那麼bootm肯定無法正常引導,會顯示Wrong Image Type for bootm command。
Image Name: RAM disk
Created: Wed Aug 23 09:09:27 2006
Image Type: ARM Linux Kernel Image (gzip compressed)
Data Size: 617981 Bytes = 603.50 kB = 0.59 MB
Load Address: 0x20008000
Entry Point: 0x20008000
10、準備好uImage,先通過超級終端下載下傳到ram裡面,檢測,然後燒寫到flash裡面。
可以發現已經成功。