U-BOOT的啟動(dòng)流程及移植
摘要:嵌入式系統(tǒng)一般沒有通用的bootloader,u-boot是功能強(qiáng)大的bootloader開發(fā)軟件,但相對也比較復(fù)雜。文中對u-boot的啟動(dòng)流程作了介紹,詳細(xì)給出了u-boot在S3C44B0開發(fā)板上的移植方法和步驟。
關(guān)鍵詞:bootloader;u-boot;嵌入式系統(tǒng);移植;S3C44B0
1 Bootloader及u-boot簡介
Bootloader 代碼是芯片復(fù)位后進(jìn)入操作系統(tǒng)之前執(zhí)行的一段代碼,主要用于完成由硬件啟動(dòng)到操作系統(tǒng)啟動(dòng)的過渡,從而為操作系統(tǒng)提供基本的運(yùn)行環(huán)境,如初始化CPU、 堆棧、存儲(chǔ)器系統(tǒng)等。Bootloader 代碼與CPU 芯片的內(nèi)核結(jié)構(gòu)、具體型號(hào)、應(yīng)用系統(tǒng)的配置及使用的操作系統(tǒng)等因素有關(guān),其功能類似于PC機(jī)的BIOS程序。由于bootloader和CPU及電路板的配置情況有關(guān),因此不可能有通用的bootloader ,開發(fā)時(shí)需要用戶根據(jù)具體情況進(jìn)行移植。嵌入式Linux系統(tǒng)中常用的bootloader有armboot、redboot、blob、u-boot等,其中u-boot是當(dāng)前比較流行,功能比較強(qiáng)大的bootloader,可以支持多種體系結(jié)構(gòu),但相對也比較復(fù)雜。bootloader的實(shí)現(xiàn)依賴于CPU的體系結(jié)構(gòu),大多數(shù)bootloader都分為stage 1和stage 2兩大部分。Bootloader的基本原理見參考文獻(xiàn)。
u-boot是sourceforge網(wǎng)站上的一個(gè)開放源代碼的項(xiàng)目。它可對 PowerPC?MPC5xx、MPC8xx、MPC82xx、 MPC7xx、MPC74xx?、ARM(ARM7、ARM9、StrongARM、Xscale)、MIPS(4kc、5kc)、X86等處理器提供支持,支持的嵌入式操作系統(tǒng)有Linux、Vx-Works、NetBSD、QNX、RTEMS、ARTOS、LynxOS等,主要用來開發(fā)嵌入式系統(tǒng)初始化代碼bootloader。軟件的主站點(diǎn)是http?//sourceforge.net/projects/ u-boot。u-boot 最初是由denx?www.denx.de?的PPC-boot發(fā)展而來的,它對PowerPC系列處理器的支持最完善,對Linux 操作系統(tǒng)的支持最好。源代碼開放的u-boot軟件項(xiàng)目經(jīng)常更新,是學(xué)習(xí)硬件底層代碼開發(fā)的很好樣例。
2 u-boot系統(tǒng)啟動(dòng)流程
大多數(shù)bootloader都分為stage1和stage2兩大部分,u-boot也不例外。依賴于CPU體系結(jié)構(gòu)的代碼(如設(shè)備初始化代碼等)通常都放在stage1?且可以用匯編語言來實(shí)現(xiàn),而stage2則通常用C語言來實(shí)現(xiàn),這樣可以實(shí)現(xiàn)復(fù)雜的功能,而且有更好的可讀性和移植性。
2.1 stage1 (start.s代碼結(jié)構(gòu))
u-boot的stage1代碼通常放在start.s文件中,它用匯編語言寫成,其主要代碼部分如下:
(1) 定義入口 。由于一個(gè)可執(zhí)行的Image必須有一個(gè)入口點(diǎn),并且只能有一個(gè)全局入口,通常這個(gè)入口放在ROM(Flash)的0x0地址,因此,必須通知編譯器以使其知道這個(gè)入口,該工作可通過修改連接器腳本來完成。
(2)設(shè)置異常向量(Exception Vector)。
(3)設(shè)置CPU的速度、時(shí)鐘頻率及中斷控制寄存器。
(4)初始化內(nèi)存控制器 。
(5)將ROM中的程序復(fù)制到RAM中。
(6)初始化堆棧 。
(7)轉(zhuǎn)到RAM中執(zhí)行,該工作可使用指令ldr pc來完成。
2.2 stage2?C語言代碼部分?
lib arm/board.c中的start armboot是C語言開始的函數(shù),也是整個(gè)啟動(dòng)代碼中C語言的主函數(shù),同時(shí)還是整個(gè)u-boot(armboot)的主函數(shù),該函數(shù)主要完成如下操作:
(1)調(diào)用一系列的初始化函數(shù)。
(2)初始化Flash設(shè)備。
(3)初始化系統(tǒng)內(nèi)存分配函數(shù)。
(4)如果目標(biāo)系統(tǒng)擁有NAND設(shè)備,則初始化NAND設(shè)備。
(5)如果目標(biāo)系統(tǒng)有顯示設(shè)備,則初始化該類設(shè)備。
(6)初始化相關(guān)網(wǎng)絡(luò)設(shè)備,填寫IP、MAC地址等。
(7)進(jìn)入命令循環(huán)(即整個(gè)boot的工作循環(huán)),接受用戶從串口輸入的命令,然后進(jìn)行相應(yīng)的工作。
3 移植實(shí)例
本系統(tǒng)開發(fā)板主要由S3C44B0X嵌入式微處理器、2MB的Flash (SST39VF160)、8MB的SDRAM(HY57V641620)、4個(gè)LED以及ARM JTAG接口組成。該開發(fā)板上與S3C44B0X相關(guān)部分的功能框圖如圖1所示。
3.1 u-boot文件下載
u-boot文件的下載有兩種方法,第一種是在Linux環(huán)境下通過CVS下載最新的文件,方法是:
$cvs-d?pserver?anonymous@cvs.sourceforge. net?/cvsroot/u-boot login
當(dāng)要求輸入匿名登錄的密碼時(shí),可直接按回車鍵
$cvs-z6-d?pserver?anonymous@cvs.source forge.net?/cvsroot/u-boot\co.P modulename
第二種是通過ftp?//ftp.denx.de/pub/u-boot/ 下載正式發(fā)布的壓縮文件。
3.2 u-boot文件的結(jié)構(gòu)
初次下載的文件有很多,解壓后存放在u-boot文件目錄下,具體內(nèi)容已在readme文件中做了詳細(xì)的介紹,其中與移植相關(guān)的主要文件夾有:
(1)CPU?它的每個(gè)子文件夾里都有如下文件:
makefile
config.mk
cpu.c 和處理器相關(guān)的代碼
interrupts.c 中斷處理代碼
serial.c 串口初始化代碼
start.s 全局開始啟動(dòng)代碼
(2)BOARD?它的每個(gè)子文件夾里都有如下文件:
makefile
config.mk
smdk2410.c 和板子相關(guān)的代碼(以smdk2410為例)
flash.c Flash操作代碼
memsetup.s 初始化SDRAM代碼
u-boot.lds 對應(yīng)的連接文件
(3)lib arm?體系結(jié)構(gòu)下的相關(guān)實(shí)現(xiàn)代碼,比如memcpy等的匯編語言的優(yōu)化實(shí)現(xiàn)。
3.3 交叉編譯環(huán)境的建立
要得到下載到目標(biāo)板的u-boot二進(jìn)制啟動(dòng)代碼,還需要對下載的u-boot1.1.1進(jìn)行編譯。u-boot的編譯一般在Linux系統(tǒng)下進(jìn)行,可用ARM-LIN-UX-GCC進(jìn)行編譯。一步一步建立交叉編譯環(huán)境通常比較復(fù)雜,最簡單的方法是使用別人編譯好的交叉編譯工具,方法如下:
(1)在http?//handhelds.org/download/toolchain下載 arm-Linux-gcc-3.3.2.tar.bz2
(2)以用戶名root登錄,將arm-linux-gcc-3.3.2.tar.bz2 解壓到 /root目錄下
# tar jxvf arm-linux-gcc-3.3.2.tar.bz2
(3)在http?//handhelds.org/download/toolchain下載 arm-linux-toolchain-post-2.2.13.tar.gz ?只是用了它的頭文件而已,主要來自內(nèi)核/linux-x.x/include下?
(4)將arm-linux-toolchain-post-2.2. 13.tar.gz 解壓到 /skiff/local/ 下
# tar zxvf arm-linux-toolchain-post-2.2.13.tar.gz
(5)拷貝頭文件到/root/usr/3.3.2/arm-linux/ 下?然后刪除 /skiff
# cp -dR /skiff/local/arm-linux/include /root/usr/3.3.2/arm-linux
# rm -fr /skiff
這樣就建立了arm linux 交叉編譯環(huán)境。
(6)增加/root/usr/local/arm/3.3.2/bin到路徑環(huán)境變量
path=$path:/root/usr/local/arm/3.3.2/bin? 可以檢查路徑變量是否設(shè)置正確。# echo $path
3.4 移植的預(yù)先編譯
移植u-boot到新的開發(fā)板上僅需要修改與硬件相關(guān)的部分即可。主要包括兩個(gè)層面的移植,第一層是針對CPU的移植,第二層是針對BOARD的移植。由于u-boot 1.1.1里面已經(jīng)包含S3C44B0的移植,所以筆者對板子myboard的移植主要是針對BOARD的移植。移植之前需要仔細(xì)閱讀u-boot目錄下的readme文件,其中對如何移植做了簡要的介紹。為了減少移植的工作量,可以在include/config目錄下選一個(gè)和要移植的硬件相似的開發(fā)板,筆者選的是b2開發(fā)板。具體步驟如下:
(1)u-boot 1.1.1 下的CPU文件夾里已經(jīng)包括了S3C44B0的目錄,其下已經(jīng)有start.s?interrupts.c以及 cpu.c?serial.c幾個(gè)文件,因而不需要建立與CPU相關(guān)的目錄。
(2)在board目錄下創(chuàng)建myboard目錄以及my-board.c、flash.c、memsetup.s和u-boot.lds 等文件。不需要從零開始創(chuàng)建,只需選擇一個(gè)相似的目錄直接復(fù)制過來,然后修改文件名及內(nèi)容即可。筆者在移植u-boot過程中選擇的是u-boot 1.1.1/board/dave/B2目錄。
(3)在include/configs目錄下添加myboard.h,在這里可放入全局的宏定義等?也不需要從頭創(chuàng)建,可以在include/configs目錄下尋找相似的CPU的頭文件進(jìn)行復(fù)制,這里筆者用的是B2.h文件來進(jìn)行相關(guān)的修改。
(4) 對u-boot根目錄下的makefile文件進(jìn)行修改,加入
myboard_config : unconfig
@./mkconfig $(@:_config=)arm S3C44B0 myboard
(5) 修改u-boot根目錄下的makefile文件,加入對板子的申明。然后在makefile 中加入myboard、LIST ARM7=″B2 ep7312 impa7 myboard″。
(6)運(yùn)行make clobber,刪除錯(cuò)誤的depend文件。
(7)運(yùn)行make myboard config。
(8)執(zhí)行到此處即表示整個(gè)軟件的makefile已建立,這時(shí)可修改生成的makefile中的交叉編譯選項(xiàng),然后打開makefile 文件,并找到其中的語句:
ifeq($(ARCH),arm)
CROSS_COMPILE=arm-linux-
end if
接著將其改成
ifeq($(ARCH),arm)
CROSS COMPILE=/root/usr/local/3.3.2/bin/arm-linux-
end if
這一步和上面的設(shè)置環(huán)境變量只要有一個(gè)就可以了。
執(zhí)行make,報(bào)告有一個(gè)錯(cuò)誤,修改myboard/flash.c中的#include ″../common/flash.c"為"u-boot/board/dave/common/flash.c″,重新編譯即可通過。
4 移植時(shí)的具體修改要點(diǎn)
若預(yù)先編譯沒有錯(cuò)誤就可以開始硬件相關(guān)代碼的移植,首先必須要對移植的硬件有清楚地了解,如CPU、CPU的控制寄存器及啟動(dòng)各階段程序在Flash?SDRAM中的布局等。
筆者在移植過程中先修改/include/config /my-board.h頭文件中的大部分參數(shù)(大部分的宏定義都在這里設(shè)置),然后按照u-boot的啟動(dòng)流程逐步修改。修改時(shí)應(yīng)熟悉ARM匯編語言和C語言,同時(shí)也應(yīng)對u-boot啟動(dòng)流程代碼有深入的了解。B2板的CPU頻率為75MHz、Flash為4Mbit、SDRAM為16Mbit、串口波特率為115200bit/s、環(huán)境變量放在EEPROM中。根據(jù)兩個(gè)開發(fā)板的不同,需要修改的有:CPU的頻率、Flash和SDRAM容量的大小、環(huán)境變量的位置等。由于參考板已經(jīng)有了大部分的代碼,因此只需要針對myboard進(jìn)行相應(yīng)的修改就可以了。與之相關(guān)的文件有/include/config /myboard.h(大部分的宏定義都在這里設(shè)置)、/board/myboard/flash.c?Flash的驅(qū)動(dòng)序?、/board/myboard /myboard.c(SDRAM的驅(qū)動(dòng)程序)、/CPU/S3C44B0/serial.c(串口的驅(qū)動(dòng)使能部分)等。
/include/config /myboard.h是全局宏定義的地方,主要的修改有:
將#define CONFIG S3C44B0 CLOCK SPEED 75改為
#define CONFIG S3C44B0 CLOCK SPEED 64;
將 #define PHYS SDRAM 1 SIZE 0x01000000 /* 16 MB */ 改為
#define PHYS SDRAM 1 SIZE 0x00800000 /* 8 MB */;
將 #define PHYS FLASH SIZE 0x00400000 /* 4 MB*改為
#define PHYS FLASH SIZE 0x00200000 /* 2 MB */;
將 #define CFG MAX FLASH SECT 256 /* max number of sectors on one chip */改為
#define CFG MAX FLASH SECT 35 ;
將 #define CFG ENV IS IN EEPROM 1 /* use EEPROM for environment vars*/改為
#define CFG ENV IS IN FLASH 1
其它(如堆棧的大小等)可根據(jù)需要修改。
由于Flash、SDRAM的容量會(huì)發(fā)生變化,故應(yīng)對啟動(dòng)階段程序在Flash、SDRAM中的位置重新作出安排。筆者將Flash中的u-boot代碼放在0x0開始的地方,而將復(fù)制到SDRAM中的u-boot代碼安排在0xc700000開始的地方。
Flash的修改不僅和容量有關(guān),還和具體型號(hào)有關(guān),Flash存儲(chǔ)器的燒寫和擦除一般不具有通用性,應(yīng)查看廠家的使用說明書,針對不同型號(hào)的存儲(chǔ)器作出相應(yīng)的修改。修改過程中,需要了解Flash擦寫特定寄存器的寫入地址、數(shù)據(jù)命令以及扇區(qū)的大小和位置,以便進(jìn)行正確的設(shè)置。
SDRAM要修改的地方主要是初始化內(nèi)存控制器部分,由start.s文件中的 cpu init crit完成CPU cache的設(shè)置,并由 board/myboard/memsetup.s中的memsetup完成初始化SDRAM。S3C44B0提供有SDRAM控制器,與一些CPU需要UPM表編程相比,它只需進(jìn)行相關(guān)寄存器的設(shè)置修改即可,因而降低了開發(fā)的難度。
串口波特率不需要修改(都是115200bit/s),直接用B2板的串口驅(qū)動(dòng)即可。串口的設(shè)置主要包括初始化串口部分,值得注意的是:串口的波特率與時(shí)鐘MCLK有很大關(guān)系,詳見CPU用戶手冊。
配置好以后,便可以重新編譯u-boot代碼。將得到的u-boot.bin通過JTAG口下載到目標(biāo)板后,如果能從串口輸出正確的啟動(dòng)信息,就表明移植基本成功。實(shí)際過程中會(huì)由于考慮不周而需要多次修改。移植成功后,也可以添加一些其它功能(如LCD驅(qū)動(dòng)等),在此基礎(chǔ)上添加功能相對比較容易。
5 結(jié)束語
u-boot是一個(gè)功能強(qiáng)大的bootloader開發(fā)軟件,適用的CPU平臺(tái)及支持的嵌入式操作系統(tǒng)很多。本文是筆者在實(shí)際開發(fā)過程中根據(jù)相關(guān)資料進(jìn)行摸索,并在成功移植了u-boot的基礎(chǔ)上總結(jié)出來的。對于不同的CPU和開發(fā)板,其基本的方法和步驟是相同的,希望能對相關(guān)嵌入式系統(tǒng)的設(shè)計(jì)人員有所幫助。
評論