蔡利平,任家富,童 銳,張敬倫
(成都理工大學 信息科學與技術學院,四川 成都610059)
嵌入式系統(tǒng)開發(fā)在當今日新月異的科技時代獨樹一幟,生活中大量的智能電子設備就是嵌入式應用的一個縮影,比如PDA、機頂盒和智能手機等。然而,在嵌入式軟件的開發(fā)中,嵌入式引導程序 (Bootloader)的設計、開發(fā)與嵌入式系統(tǒng)的硬件息息相關,這個特性決定了不可能用一個通用程序作為眾多嵌入式系統(tǒng)的引導程序。在這樣的背景下,針對不同的開發(fā)環(huán)境設計不同的嵌入式系統(tǒng)引導程序成為首要問題,本文根據實際的情況,詳細的分析了嵌入式引導程序的引導、啟動原理,同時結合S3C2410開發(fā)板和 U-Boot-1.1.6引導程序,分析從 Nand Flash啟動的具體流程,修改并完成了 U-Boot從Nand Flash啟動的移植。
嵌入式軟件從應用角度可以劃分為4個層次:引導程序 (Bootloader)、內核、文件系統(tǒng)以及嵌入式應用軟件(如GUI)。Bootloader是嵌入式系統(tǒng)中第一個被運行的程序,其功能是初始化部分硬件、為隨后加載的系統(tǒng)內核準備相關的系統(tǒng)參數 (機器類型ID和啟動參數標記列表在RAM中的地址)、加載內核到內存并將系統(tǒng)的控制權移交給內核?,F在支持ARM體系結構的bootloader很多,比如Vivi、RedBoot、BLOB以及U-Boot等。不同的Bootloader在支持的體系結構和種類上有所不同,本文主要是針對U-Boot進行分析與移植。U-Boot是德國DENX研究中心開發(fā)設計的,其對現在市場上主流的操作系統(tǒng)、CPU都能提供良好的支持,功能相當的強大。U-Boot的文件組織方式與Linux內核相同,將功能或者特性相同的源文件放在一起,方便對源文件的管理與閱讀。根據文件的不同作用,本人將U-Boot中所有的源文件相對的劃分為下面的3個層次。如圖1所示。
之所以這樣分層,是因為:上層包含的/cpu和/board文件決定了系統(tǒng)所使用的ARM芯片類型以及與開發(fā)板相同或者相近的板級體系結構,如S3C2410開發(fā)板,相近的文件就 是/cpu/arm920t和/board/smdk2410,而/lib_xxx文件主要包含的是庫文件,屬于必不可少的部分;中間層文件include/configs/xxx.h中定義了眾多的宏,其中定義的配置宏和參數宏在代碼的編譯過程中將決定哪些代碼段將被包含,哪些代碼段將不被包含,控制Bootloader所實現的功能,起一個承上啟下的作用;底層主要包含了相關的驅動程序以及一些通用函數和接口函數。
在嵌入式系統(tǒng)中,根據引導系統(tǒng)存儲的位置,引導系統(tǒng)啟動主要分為有兩種方式:Nor Flash引導和Nand Flash引導。這兩種引導方式不管是從硬件連接還是從軟件設計都有本質的不同,現在主流的引導程序基本上都支持從Nor Flash的啟動引導,軟件技術的實現相對比較成熟;但是對Nand Flash的啟動支持還不是很完善,要能夠從Nand Flash啟動,需要引導程序和開發(fā)板都支持從Nand Flash啟動。本文使用的U-Boot-1.1.6并不支持從Nand Flash啟動的,而開發(fā)板S3C2410的硬件特性支持從Nand Flash啟動。本文將通過分析U-Boot的啟動流程,最終實現U-Boot從Nand Flash的啟動與移植。
Bootloader的啟動一般可以分為兩個階段。第一階段主要是對部分硬件 (關閉看門狗、關中斷、設置時鐘和初始化存儲設備等)的初始化、拷貝引導程序U-Boot自己全部的代碼到SDRAM中以及為第二階段的執(zhí)行準備硬件環(huán)境 (清除BSS段、設置堆棧等),用匯編代碼實現。第二階段繼續(xù)完成對外圍硬件設備的檢測與初始化,為內核引導提供硬件環(huán)境和引導參數。U-Boot在第二階段對Nor Flash和對Nand Flash的支持是相同的,因此,支持Nand Flash啟動的代碼修改主要集中在U-Boot啟動的第一階段。為了得出U-Boot從Nor Flash引導與從Nand Flash引導的不同之處,這里結合韓國Mize公司的Vivi bootloader,Vivi最初主要是針對S3C2410X處理器的,支持從Nand Flash啟動的引導,通過分析,第一階段的引導流程如圖2所示。
圖2中方向①、②指明了Nand Flash與Nor Flash在引導程序第一階段的不同之處,在程序中體現在/cpu/arm920t/start.S源文件的重定位代碼段,源文件start.S也是U-Boot程序的入口文件,具體比較如圖3所示。
U-Boot從Nor Flash啟動的引導系統(tǒng),只需要根據具體硬件的配置,更改少量的配置選項即可完成引導工作。通過上面的分析,為了實現Nand Flash引導啟動需要修改U-Boot代碼完成以下幾個方面的問題:
(1)保證U-Boot的前4k代碼不僅能夠初始化相關的硬件,還要能夠將存儲在Nand Flash中的所有U-Boot代碼拷貝到SDRAM中,這也是第一階段的主要任務;
(2)在配置文件/include/configs/xxx.h中添加相關的宏,確定啟動是從Nand Flash中進行,以及確定U-Boot代碼在SDRAM中的起始位置、設置堆棧大小;
(3)最后需要實現對Nand Flash讀寫操作的命令支持,能夠使U-Boot在控制終端使用Nand Flash命令對Nand Flash進行相關的操作。
圖3 Nor Flash引導和Nand Flash引導的比較
系統(tǒng)引導啟動方式 (Nor Flash or Nand Flash引導)是由引腳OM [1:0]來確定的,如果OM [1:0]為0x0,則是從Nand Flash引導;如果OM [1:0]的值為0x1,0x2則是從Nor Flash引導,這可以通過跳線來設置,有的開發(fā)板直接使用Nand Flash硬件連接。系統(tǒng)如果從Nand Flash啟動,由于Nand Flash接口的特殊性,系統(tǒng)上電后會自動將Nand Flash前4k的代碼復制到S3C2410內部集成的SRAM中,然后跳到這個SRAM緩沖區(qū)中0x0開始執(zhí)行,這部分代碼需要完成硬件的初始化并將U-Boot代碼拷貝到SDRAM中后,然后跳轉到SDRAM中執(zhí)行。這里首先修改 源文件 uboot/board/s3c2410/start.S,在其中添加對Nand Flash的初始化代碼,然后完成 U-Boot的拷貝:
coyp_myself_uboot:
(Nand Flash的初始化代碼)
……
ldr r0,=UBOOT_RAM_BASE
//這是將U-Boot代碼拷貝到SDRAM中的起始地址
mov r1,#0x0
//這是U-Boot在Nand Flash中的起始地址,即0x0
mov r2,#0x20000
//這是U-Boot代碼的長度
bl nandTOsdram
//完成U-Boot到SDRAM拷貝的C函數
……
跳轉到源文件nand_copy.c中的拷貝函數nandTOsdram中。這里的寄存器r0,r1,r2依次作為nandTOsdram的第一、第二和第三個參數。在/board/s3c2410/下添加文件nand_copy.c,主要代碼如下:
……
int nandTOsdram (unsigned char*buf,unsigned long start_addr,int size){
int i,j;
if((start_addr & NAND_BLOCK_MASK)‖ (size&NAND_BLOCK_MASK)){
return-1; /*invalid alignment*/
}
/*chip Enable*/
NFCONF &= ~0x800;
for(i=0;i<10;i++);
for(i=start_addr;i< (start_addr+size);){
/*READ0*/
NFCMD=0;
/* Write Address*/
NFADDR =i &0xff;
NFADDR= (i>>9)&0xff;
NFADDR= (i>>17)&0xff;
NFADDR= (i>>25)&0xff;
wait_idle ();
for(j=0;j< NAND_SECTOR_SIZE;j++,i++){
*buf= (NFDATA &0xff);
buf++;
}
}
/*chip Disable*/
NFCONF|=0x800; /*chip disable*/
return 0;
}
通過在/cpu/arm920t/start.s中添加的Nand Flash初始化代碼以及C源文件nand_copy.c解決了U-Boot從Nand Flash啟動的第一個問題。
配置文件/include/configs/xxx.h控制整個開發(fā)板的編譯選項,主要包括兩類:以CONFIG_開頭的文件用于選擇CPU、SOC、開發(fā)板類型等,作為系統(tǒng)框架設計的一個選項;還有一類是以CFG_開頭的宏,作為系統(tǒng)的參數出現,如設置緩沖池的大小、提示符等。為了獲得U-Boot Nand Flash啟動的支持,需要在配置文件中添加以下幾個宏:
#define CONFIG_S3C2410_NAND_BOOT 1//控制編譯從Nand Flash啟動的代碼
#define STACK_BASE 0x33f00000//定義堆棧在SDRAM中的位置以及長度
#define STACK_SIZE 0x8000
#define UBOOT_RAM_BASE 0x33f80000//U-Boot代碼在SDRAM中的起始位置
#define NAND_CTL_BASE 0x4e000000//Nand Flash各個控制器的地址的定義
#define bINT_CTL (Nb) __REG (INT_CTL_BASE+ (Nb))
/
*offset*/
#define oNFCONF 0x00
#define oNFCMD 0x04
#define oNFADDR 0x08
#define oNFDATA 0x0c
#define oNFSTAT 0x10
#define oNFECC 0x14
經過上述兩步的修改,U-Boot已經實現了從Nand Flash的啟動,但是在控制終端并不能通過U-Boot的命令來對Nand Flash進行讀寫操作。
U-Boot對Nand Flash的讀寫操作命令并沒有給予完整的支持。要先在配置文件中打開Nand Flash命令的控制宏:
#define CONFIG_COMMANDS\
(CONFIG_CMD_DFL | \
CFG_CMD_CACHE | \
CFG_CMD_NAND | 去掉之前的注釋符號,使的CFG_CMD_NAND可用
/
*CFG_CMD_EEPROM|*/\
/*CFG_CMD_I2C |*/\
……)
同時,由于U-Boot默認的代碼不能識別本文開發(fā)板上的Nand Flash K9F1208U0A芯片型號,還需要在文件/include/linux/mtd/nand_ids.h中的結構體添加如下代碼,以識別芯片型號:
static struct nand_flash_dev nand_flash_ids[]= {
……
{"Samsung K9F1208U0A",NAND _MFR _SAMSUNG,0x76,26,0,3,0x4000,0},}
對 Nand Flash的讀寫操作在 U-Boot-1.1.6中有新舊兩套代碼,/driver/nand是新代碼文件,/driver/nand_legacy是舊代碼文件,如果在配置文件中定義了宏CFG_NAND_LEGACY,則通過舊代碼部分獲得對Nand Flash的支持,否則使用新代碼支持Nand Flash的底層操作,本文使用的是新代碼部分。在代碼中還需要實現函數board_nand_init()的定義,實現對Nand Flash的底層操作,這個函數在文件/driver/nand/nand.c中只進行了聲明:
……
extern void board_nand_init (struct nand_chip *nand);
……
沒有定義的具體代碼,添加源文件nflash.c并在此源文件中實現board_nand_init函數,函數的調用過程如圖4所示。
圖4 board_nand_init函數的調用過程
對Nand Flash底層函數的管理都是通過結構體struct nand_chip實現的,在board_nand_init函數中就是要實現這個結構體中各個底層函數,但是并不用實現結構體的每一個成員變量,這里必須要實現的結構體成員有:
讀寫信號nand->IO_ADDR_R= (void*)&s3c2410_mynand->NFDATA,nand->IO_ADDR_W= (void*)&s3c2410_mynand->NFDATA;控制信號函數nand->hwcontrol=s3c2410_nand_control_signal;芯片狀態(tài)函數nand->dev_ready=s3c2410_nand_if_busy;片選信號函數 nand->select_chip=s3c2410_nand_select_chip以及位寬options的設置。到這里就完成了U-Boot從Nand Flash啟動的代碼修改,也實現了在終端對Nand Flash命令的支持。
在U-Boot的頂層目錄執(zhí)行命令:
make distclean
make s3c2410_config
make CROSS_COMPILE=arm-linux-
生成目標文件uboot.bin,將其通過并口燒寫到Nand Flash中,然后重啟,控制終端顯示如下:
U-Boot 1.1.6(Nov 20 2010-15:32:38)
U-Boot code:33F80000->33F9A768BSS:->33F9EF18
DRAM: 64 MB
NAND: 64 MB
In: serial
Out: serial
Err: serial
CAI_s3c2410#
到這里就成功的完成了U-Boot的修改與移植。這里還有幾個問題需要注意:為了能夠在控制終端顯示U-Boot在SDRAM中段的分布,需要將文件/lib_arm/board.c中的debug("U-Boot code:%08lX-> %08lX BSS:-> %08lX\n",_armboot_start,_bss_start,_bss_end)換成printf("U-Boot code:%08lX-> %08lX BSS:-> %08lX\n",_armboot_start,_bss_start,_bss_end);本開發(fā)板上沒有nor flash,因此要在配置文件中注釋掉flash的定義,并且注釋掉/common/cmd_bootm.c中關于imls命令的程序段和/common/cmd_flash.c中的程序段。
結合硬、軟件開發(fā)的嵌入式系統(tǒng),分析、設計其啟動流程是開發(fā)過程中第一個需要解決的問題。U-Boot引導程序以清晰明了的流程,詳細的描述了怎么實現引導的具體過程。本文同時結合了Vivi的啟動流程分析,實現了支持Nand Flash啟動引導的U-Boot,詳細的介紹怎么實現這個程序的修改過程。通過對U-Boot啟動的分析能夠深刻的理解到軟件是怎么實現對硬件的操作,綜合的應用了所學的知識,為開發(fā)嵌入式系統(tǒng)獲得直接經驗。
[1]DU Chunlei.The architecture of ARM and program [M].Beijing:Tsinghua University Press,2009:58-223 (in Chinese).[杜春雷.ARM體系結構與編程 [M].北京:清華大學出版社,2009:58-223.]
[2]LAI Yushu.ARM MPU and applications[M].Beijing:Publishing House of Electronics Industry,2007:75-150 (in Chinese).[賴于樹.ARM微處理器與應用開發(fā) [M].北京:電子工業(yè)出版社,2007:75-150.]
[3]WANG Minghu.The exploitation induction of ARM embedded Linux[M].Beijing:Publishing House of Electric Power China,2008:55-102 (in Chinese).[汪明虎.ARM嵌入式Linux應用開發(fā)入門 [M].北京:中國電力出版社,2008:55-102.]
[4]WEI Dongshan.The app exploitation entirety manual of embedded Linux[M].Beijing:The Press of People Postal and Electricity,2008:240-292(in Chinese).[韋東山.嵌入式Linux應用開發(fā)完全手冊 [M].北京:人民郵電出版社,2008:240-292.]
[5]SUN Qiong.The application exploitation details of embedded Linux[M].Beijing:The Press of People Postal and Electricity,2006:116-121(in Chinese).[孫瓊.嵌入式Linux應用程序開發(fā)詳解[M].北京:人民郵電出版社,2006:116-121.]
[6]Stephen Prate.C primer plus [M].Beijing:Posts &Telecom Press,2010:354-376 (in Chinese).[Stephen Prate.C primer plus[M].北京:人民郵電出版社,2010:354-376.]
[7]DU Haixing.The analysis and transplant of embedded Bootloader based ARM [J].Microcomputer Information,2010,26 (10-2):58-59(in Chinese).[杜海星.基于ARM的嵌入式Bootloader分析與移植 [J].微計算機信息,2010,26 (10-2):58-59.]
[8]ZHAN Rongkai.The startup secret of embedded Bootloader[EB/OL].http://www.ibm.com/developerworks/cn/linux/l-btloader/,2010 (in Chinese).[詹榮開.嵌入式 Bootloader啟 動 內 幕 [EB/OL].http://www.ibm.com/developerworks/cn/linux/l-btloader/,2010.]
[9]Tekkaman Ninja.Transplant U-Boot 1.2.0 to Weichuang 2410-S (S3C2410A) [EB/OL].http://blog.chinaunix.net/u1/34474/showart.php?id= 363269,2010 (in Chinese).[Tekkaman Ninja.移植 U-Boot.1.2.0到博創(chuàng)2410-S(S3C2410A) [EB/OL].http://blog.chinaunix.net/u1/34474/showart.php?id=363269,2010.]
[10]QIU Xuehong.The truth of microcomputer and interface technic[M].Xi’an:Xi’dian University Press,2007:66-134(in Chinese).[裘雪紅.微型計算機原理及接口技術 [M].西安:西安電子科技大學出版社,2007:66-134.]
[11]ZHANG Shi.The tutorial of ARM embedded system [M].Beijing:China Machine Press,2008:35-66 (in Chinese).[張石.ARM嵌入式系統(tǒng)教科書 [M].北京:機械工業(yè)出版社,2008:35-66.]
[12]WU Shili.The resolve and practice of embedded Linux App exploitation [M].Beijing:China Machine Press,2008:135-146 (in Chinese).[吳士力.嵌入式LINUX應用開發(fā)全程解析與實戰(zhàn)[M].北京:機械工業(yè)出版社,2008:135-146.]
[13]Qing Ting Dian Shui.The startup process of U-Boot[EB/OL].http://wenku.baidu.com/view/4428024ae45c3b3567ec8b4d.html,2010(in Chinese).[蜻蜓點水.U-Boot啟動過程 [EB/OL].http://wenku.baidu.com/view/4428024ae45c3b3567ec8b 4d.html,2010.]
[14]CHU Shi Feng Mang.The manual of transplanting U-Boot to S3C2410 [EB/OL].http://wenku.baidu.com/view/1c2cb28da 0116c175f0e48f3.html,2010 (in Chinese).[初試鋒芒.UBOOT移植S3C2440完全手冊 [EB/OL].http://wenku.baidu.com/view/1c2cb28da0116c175f0e48f3.html,2010.]
[15]lien5.The Nand Flash drive analysis based on S3C2410 [EB/OL].http://hi.baidu.com/52hack/blog/item/675119df980b401b62279809.html,2010 (in Chinese).[lien5.對S3C2410平臺上 Nand Flash的驅 動 分 析 [EB/OL].http://hi.baidu.com/52hack/blog/item/675119df980b401b62279809.html,2010.]