摘要:用U-Boot構建嵌入式系統的引導加載程序,在對U-Boot的啟動工作機理進行了簡略分析后,針對基于SEP3203 的目標板對U-Boot 作了具體的修改和移植。要在U-Boot里增加了若干測試命令,并在U-Boot里增加了中斷處理程序,通過SEP3203的timer,每隔一毫秒進入中斷處理進行喂狗。并在剛開始的一段代碼里增加了啟動Nucleus代碼。在U-Boot里增加了應用結果表明,移植后的U-Boot 在目標板上運行良好,可成功引導Nucleus內核。
關鍵詞:U-Boot;移植;內核;SEP3203;嵌入式系統
中圖分類號:TP316文獻標識碼:A 文章編號:1009-3044(208)22-809-05
Start Analysis and Porting of U-Boot Based on SEP3203
ZHANG Guo-xiang, ZHONG Rui
(Deptement of Electronic Science and Engineering,Southeast University,Nanjing 210096, China)
Abstract:This paper develops a bootloader for embedded system with the U-Boot. After analyzing the booting mechanism of U-Boot, the modification and porting in an embedded system board based on SEP3203 are done in detail. We add some test commands ,and enable interrupt by setting SEP3203 and do irq for watchdog every one millisecond. The application shows the U-Boot runs well and can lead Nucleus kernel successfully.
Key words:U-Boot; poting; kernel; SEP3203; embedded system
Bootloader是在操作系統運行之前執行的一段小程序。通過這段小程序,可以初始化硬件設備,建立內存空間映射表,從而建立適當的系統軟硬件環境,為最終調用的操作系統內核做好準備。但對于兩塊不同的嵌入式板而言,即使它們使用同一種處理器,要想讓運行在一塊板子上的Bootloader程序也能運行在另一塊板子上,一般也都需要修改Bootloader的源程序。
本文基于SEP3203的嵌入式目標板和U-Boot源碼資源,分析了U-Boot的啟動過程,介紹了U-Boot的移植方法和具體操作,最后講述如何引導內核啟動。
1 U-Boot簡介
最早,DENX軟件工程中心的Wolfgang Denk基于8xxrom的源碼創建了PPCBOOT過程,并且不斷添加處理器的支持。后來,Sysgo Gmbh把ppcboot移植到ARM平臺上,創建了ARMboot工程。然后ppcboot工程和armboot工程為基礎,創建了U-Boot工程。
現在U-Boot己經能夠支持PowerPC,ARM,X86,MIPS體系架構的上百種開發板,已經成為功能最多,靈活性最強并且開發最積極的開放源碼Bootloader。目前仍然由DENX的Wolfgang Denk維護。
U-Boot移植一般都是針對嵌入式目標板的硬件資源,主要是CPU,FLASH和SDRAM等情況,以盡可能一致的原則,在U-Boot源碼中,找到一個與目標板為同一個或同一系列處理器的目標板模板,在此基礎上再針對具體開發板對程序作相應的修改。這里采用U-Boot1.1.1版本,該版本支持基于Arm7TDMI處理器配置,并提供了一個目標模板,即U-Boot源碼下的board/s3c44b0模板。
2 U-Boot源碼結構與啟動分析
U-Boot源程序在頂層目錄下共有18個子目錄,分別存放和管理不同的源程序。這些目錄中所要存放的文件有其規則,可以分為三類。
第一類目錄與處理器體系結構或者開發板硬件直接相關;第二類目錄是一些通用的函數或者驅動程序;第三類目錄是U-Boot頂層目錄下各級目錄存放原則。(如表1)
接下來用s3c44b0來分析U-Boot的啟動過程,Borad/s3c44b0目錄下的u-boot.lds連接腳本決定了入口函數位于cpu/s3c44b0/start.s中。這就是U-Boot上電執行的第一個程序,接下來U-Boot共經歷了三個階段。
1)在Flash中運行匯編程序,進行基本硬件初始化,并將Flash中的啟動代碼復制到SDRAM中,同時創造環境準備運行C程序,具體工作流程如圖1所示。
2)跳轉到SDRAM中執行,對硬件進行初始化,并向顯示終端輸出啟動信息;start_armboot是U-Boot執行的第一個C語言函數,它位于lib_arm/board.c中,主要完成系統初始化工作,進入主循環,處理用戶輸入的命令。具體工作流程如圖1,2所示。
全局變量結構體gd主要用來保存開發板信息,終端存在標志位,環境變量結構體起始地址,環境變量校驗標志位,frame buffer基地址等。它是指向gd_t結構體的指針,gd_t結構體定義在include\\asm-asm\\global_data.h中。
硬件初始化中執行函數及各函數作用如下所示:
board_init: 基本的板級相關配置,主要對TC控制器設置;
interrupt_init: 中斷處理初始化,主要對TC控制器作相應設置;
env_init:設置環境變量,初始化環境;
init_baudrate: 制定串口的波特率;
serial_init:串口初始化設置;選擇通訊端口,設置串口波特率和工作方式;
console_init_f: 設置gd->have_console=1,表示可以使用串口通訊控制臺;
display_banner: 在控制臺輸出U-Boot信息;
dram_init:設置SDRAMA的啟示地址和大小;
display_dram_config: 在控制臺輸出SDRAM信息;
flash_init: 設置FLASH芯片ID號,每個扇區起始地址等信息,將信息送到相應的結構體中;對FLASH中U-BOOT和環境變量存儲扇區做軟件寫保護;
display_flash_config(size): 在上位機終端輸出FLASH大小。
■
圖1 start.s函數執行流程 圖2 start_armboot函數執行流程
3)將內核映像和根文件系統映像從flash拷貝到SDRAM中,為內核設置啟動參數,進入內核的入口函數。
U-Boot作為Bootloader,具備多種引導內核啟動的方式。常用的go和bootm命令可以直接引導內核映像啟動。U-Boot于內核的關系主要是內核啟動過程中參數的傳遞。go命令調用do_go()函數,跳轉到某個地址執行。如果這個地址準備好了自引導內核映像,就可以啟動了。盡管go命令可以帶變參,實際使用時一般不用來傳遞參數。bootm命令調用do_bootm函數。這個函數專門用來引導各種操作系統映像,可以支持引導Linux,vxWorks,QNX等操作系統。本文主要用go命令的方法來引導nucleus。
3 基于SEP3203 U-Boot的移植
3.1目標板介紹
本目標板以由東南大學asci中心自主研發的SEP3203作為微處理器,板上存儲系統包括NOR Flash,SDRAM等;外圍支持JTAG,顯示等接口。
目標板硬件架構如圖3所示。
芯片型號:
CPU:SEP3203F50 75MHZ
NOR Flash: intel TE28F160 2M
SDRAM: SAMSUNG k4S641632H 8M
內存分布:
Flash起始地址為 0x20000000
SDRAM起始地址為 0x30000000
SEP3203剛啟動時把地址0x20000000重映射到0地址。
板子外置了看門狗,所以在U-Boot中要開中斷定時喂狗。
3.2 源代碼修改
我們從U-Boot源代碼的編譯過程來修改源代碼。
編譯分為兩個步驟,第一步配置,執行make ITSN_s3c44b0_config,以產生一些編譯配置文件(.mk 文件)和相應的一些頭文件(.h文件)。
第二步編譯,執行命令make這一步驟生成了三個文件,其中:u-boot,elf文件格式,u-boot.bin是二進制文件,u-boot.map為符號表。
在執行make ITSN_s3c44b0_config時,ITSN_s3c44b0_config是Makefile的目標,定義如下:
ITSN_s3c44b0_config:unconfig
@./mkconfig $(@:_config=) arm s3c44b0 s3c44b0 itsn
unconfig:
@rm -f include/config.h include/config.mk board/*/config.tmp
顯然執行make ITSN_s3c44b0_config時,先執行unconfig目標,刪除上次配置生成的文件。然后執行命令:@./mkconfig $(@:_config=) arm s3c44b0 s3c44b0 itsn,mkconfig是是頂層目錄下的mkconfig腳本文件,后面五個是傳入的參數。注意第一個參數的$(@:_config=),$@是本次配置的目標ITSN_s3c44b0_config,然后用替換命令字符串_config替換為空,最后得到ITSN_s3c44b0。腳本程序主要做三件事,見下面分析:
在include文件夾下建立相應的文件軟連接,
rm -f asm
ln -s asm-$2 asm
rm -f asm-$2/arch
ln -s arch-$3 asm-$2/arch
if [ \"$2\" = \"arm\" ] ; then
rm -f asm-$2/proc
ln -s proc-armv asm-$2/proc
fi
生成Makefile包含文件include/config.mk,內容很簡單,定義了四個變量:
echo \"ARCH= $2\" >config.mk
echo \"CPU = $3\" >> config.mk
echo \"BOARD = $4\" >> config.mk
[ \"$5\" ] echo \"VENDOR = $5\" >> config.mk
生成include/config.h頭文件,只有一行:
echo \"#include
mkconfig腳本文件的執至此結束。繼續分析Makefile剩下部分。
包含include/config.mk,其實就相當于在Makefile里定義了上面四個變量。
包含頂層目錄下的config.mk,這個文件里面主要定義了交叉編譯器選項和編譯規則。其中對移植最重要的因該是指定板子的鏡像連接時內存的基地址。
sinclude$(TOPDIR)/board/$(BOARDDIR)/config.mk,
其內容為,
TEXT_BASE = 0x30700000(移植后的基地址)
PLATFORM_CPPFLAGS += -Uarm
鏈接選項LDFLAGS:LDFLAGS += -Bstatic -T $(LDSCRIPT) -Ttext $(TEXT_BASE) $(PLATFORM_LDFLAGS)
回到頂層makefile文件,makefile需要的目標文件。OBJS = cpu/$(CPU)/start.o,順序很重要,start.o必須放在第一位。需要的庫文件略。
最后分析下最關鍵的u-bootELF文件鏡像的生成:依賴目標depend:生成各個子目錄的.depend文件,.depend列出每個目標文件的依賴文件。生成方法,調用每個子目錄的make _depend
depend dep:
@for dir in $(SUBDIRS) ; do $(MAKE) -C $$dir .depend ; done
依賴目標$(OBJS),采用了默認規則。依賴目標$(LIBS),這個目標太多,都是每個子目錄的庫文件*.a,通過這行相應子目錄下的make來完成:
$(LIBS):
$(MAKE) –C $(dir $(subst $(obj),,$@))
依賴目標$(LDSCRIPT)即連接腳本文件位于board/itsn/s3c44b0/u-boot.lds,定義了連接時各個目標文件是如何組織的。
執行連接命令,其實是把start.o和各個子目錄makefile生成的庫文件按照LDFLAGS連接在一起,生成ELF文件u-boot。
對于各個子目錄的makefile文件,主要是生成*.O文件然后執行AR生成對應的庫文件。
整個makefile剩下的內容就是各種不同的開發板的*_config:目標的定義了。
分析完makefile下面根據目標板的配置,來修改以下U-Boot源碼文件:
1)board/Itsn/S3c44b0/Config.mk 。修改TEXT_BASE = 0x30700000 。因為SEP3203外接的SDRAM基地址為0x30000000,大小為8M 。
2)cpu/S3c44b0/start.S 。該文件里是匯編代碼,主要完成完成cpu的設置,存儲器的設置,自搬遷(把代碼拷到TEXT_BASE處),以及堆棧的設置,還完成中斷向量表的設置。這里要修改兩處:
Cpu_init_crit:這里添加cpu時鐘的初始化為70MHz,配置16位的Nor Flash 。
因為沒有使用SEP3203內部的看門狗,而外置看門狗,所以不能關閉看門狗因此要看中斷喂狗。所以添加如下中斷處理程序。
.globl irq_handler
irq_handler:
SUBlr, lr, #4
STMFDsp!, {r0-r12, lr}
MRS r4, spsr
STMFD sp!, {r4}
BLdo_irq
LDMFD sp!, {r4}
MSR spsr, r4
LDMFDsp!, {r0-r12, pc}^
添加啟動nucleus代碼如下:
.globl run_nucleus
run_nucleus:
ldrr3, =0x00000000
ldrr1, =0x30000000
ldrr2, =0x20170000
LOOP:
ldrr4, [r2], #4
strr4, [r1], #4
add r3, r3, #1
cmpr3,#0x18000
bneLOOP
ldrr1, =0x1000b07c
ldrr2, =0xffffffff
strr2,[r1]
REMAP:
ldrr1, =0x11000010
ldrr2, =0x0000000b
strr2, [r1]
ldr pc, =0x30000020
3)include/configs/ITSN_s3c44b0.h 。該頭文件包含了SDRAM的一些設置和定義;
修改串口的波特率:
#define CONFIG_BAUDRATE 9600
修改打印信息:
#define CFG_PROMPT “Sep3203==>”
修改默認下載地址:
#define CFG_LOAD_ADDR 0x30008000
修改Flash,SDRAM起始的地址,與大小:
#define PHYS_SDRAM_1 0x30000000
#define PHYS_SDRAM_1_SIZE 0x00800000
#define PHYS_FLASH_1 0x20000000
#define PHYS_FLASH_SIZE 0x00200000
4)board/Itsn/Common/flash.c 。該程序完成的功能包括Flash初始化,打印Flash信息,Flash擦除和Flash寫入等操作。可在參考已有 Flash驅動的基礎上,結合目標板flash數據手冊,進行適當修改;
在flash_get_offsets函數中添加下面的代碼:
if (info->flash_id FLASH_BTYPE) {
/* set sector offsets for bottom boot block type*/
info->start[0] = base + 0x00000000;
info->start[1] = base + 0x00004000;
info->start[2] = base + 0x00006000;
info->start[3] = base + 0x00008000;
for (i = 4; i < info->sector_count; i++) {
info->start[i] = base + (i * 0x00010000) - 0x00030000;
}
上面的代碼設置flash中每塊的起始地址。
在按照write_word,flash_erase函數原型修改flash的擦除和寫入函數。
5)cpu\\s3c44b0\\serial.c 。在這里初始化串口驅動,波特率設為9600 。按照軟件查詢的方式實現串口的讀寫。
6)cpu\\s3c44b0\\Interrupts.c 。
TCFG0 = 0x000000E9;
TCFG1 = 0x00000004;
TCON = 0x00000900;
TCNTB1 = TIMER_LOAD_VAL;
TCMPB1 = 0;
TCON = 0x00000B00;
TCON = 0x00000900;
lastdec = TCNTB1 = TIMER_LOAD_VAL;
timestamp = 0;
這里time0用于中斷喂狗,time1通過查詢來做為軟定時器。
7)lib_arm\\board.c 。在這里添加兩個函數,
void install_irq_handler( void (*isr)(void) ),設置中斷跳轉向量。void do_irq( void ),中斷喂狗程序。在void start_armboot(void)函數里調用install_irq_handler之前想要進行remap,這樣設置的中斷向量在sdram中。
8)common\\main.c 。在main_loop函數中調用啟動nucleus函數run_nucleus(),定義在start.S中。
9)添加命令。U-Boot的每個命令都是通過U_Boot_CMD定義的。這個宏在include/command.h頭文件中定義,每一個命令定義一個cmd_tbl_t結構體。
在include/cmd_confdefs.h中定義了所有U-Boot命令的標志位,通過它可以屏蔽命令。可以在common目錄下創建自己的文件,最后不要忘了在Makefile中添加編譯的目標文件。
至此,U-Boot源碼文件修改完畢。
4 結束語
本文結合分析U-Boot的運行機理,研究了在基于SEP3203的嵌入式系統板上的移植方法及具體的軟件修改方法。本文選用的Bootloader U-Boot目前能穩定的運行在使用的嵌入式系統板上。通過U-Boot可以實現串口與PC通信,查看,修改內存,引導nucleus嵌入式操作系統等功能。前期的移植工作是嵌入式系統開發的必要環節,為以后的軟件的升級提供了方便。
參考文獻:
[1] 焦玉全,黃鄉生,鮑玉軍. U-Boot在S3C2410上的移植[J]. 電子設計應用2006,(3):126-128.
[2] Tansley D.Linux and Unix Shell Programming[M]. 北京:機械工業出版社,2000.6.
[3] 時龍興,凌明,王學香. 嵌入式系統[M]. 北京:電子工業出版社,2006.10.
[4] Yagbmour K. 構建嵌入式Linux系統[M]. 北京:中國電力出版社,2004.12.
[5] 張進,姜威. U-Boot的啟動流程及移植移植[J]. 國外電子元器件,2005,(5)11-14.
[6] 孫紀坤,張小泉. 嵌入式Linux系統開發技術詳解-基于ARM[M]. 北京:人民郵電出版社,2006.8.
[7] 陳渝,李明,楊曄. 源碼開放的嵌入式系統軟件分析與實踐[M]. 北京:北京航空航天大學出版社,2004.9.
[8] 周永宏,王成飛,何志敏. ARM7TDMI-S在嵌入式系統中的Bootloader代碼設計[J]. 單片機與嵌入式系統應用,2004,(9):27-29.
[9] 馬學文,朱名日,程小輝. 嵌入式系統中的設計與實現[J].計算機工程,2005,31(7):96-98.
[10] 岳曉慶,張其善,常青. 串口擴展技術在嵌入式系統中的實現[J].電子測量技術,2006,29(2):45-46.