李鵬勃,靳伍銀
(蘭州理工大學機電工程學院,甘肅蘭州730050)
隨著計算機技術和微電子技術的快速發(fā)展,嵌入式系統(tǒng)在控制、模式識別、傳感技術、電子、電氣、計算機、機械等多個學科領域內(nèi)都得到了廣泛的應用。嵌入式系統(tǒng)能夠根據(jù)應用的要求,將操作系統(tǒng)和功能軟件集成于計算機硬件系統(tǒng)中,實現(xiàn)軟件與硬件一體化,而且嵌入式系統(tǒng)具有高實時性,吸引了越來越多的研究人員投入到嵌入式領域的研發(fā)工作中[1]。嵌入式系統(tǒng)的研發(fā)工作主要分為:引導程序、內(nèi)核移植、文件系統(tǒng)、驅(qū)動開發(fā)4 個環(huán)節(jié),其中引導程序是后面3 個環(huán)節(jié)的基礎,完成了底層硬件的初始化和存儲器等硬件的配置,因此引導程序的設計不但是嵌入式系統(tǒng)設計的難點,同時也是嵌入式系統(tǒng)運行的基本前提[2]。鑒于以上分析,作者在ARM9 S3C2440 開發(fā)平臺下,對U-Boot 進行移植分析。
ARM9 S3C2440 提供了完整的底層軟件和嵌入式操作系統(tǒng)的支持及其應用界面。該系統(tǒng)開發(fā)板主要由S3C2440A 嵌入式微處理器、64 MB 的SDRAM、2 MB的NOR Flash (SST39VF160 或SST39VF1601)、128 MB 的NAND Flash、2 個標準串口、1 個擴充串口、2個以太網(wǎng)接口、2 個USB 接口、CAN 總線接口、SD卡接口、CF 卡接口、IDE 接口、JTAG 接口、VGA 接口、LCD 接口、攝像頭接口、時鐘電路和電源電路等組成[3]。此平臺不僅提供了完整的底層驅(qū)動,提供了Linux2.6.24 下各外圍接口的驅(qū)動,還提供通過圖形接口控制這個操作系統(tǒng)下各驅(qū)動的范例。
S3C2440 開發(fā)平臺選用的中央處理器為三星S3C2440A,主頻為400 MHz。S3C2440 支持兩種啟動模式:一種是從NAND FLASH 啟動;一種是從外部nGCS0RU 晶片選擇的NOR FLASH 啟動。啟動模式的選擇,主要是通過J21 (OM0)JUMP 來決定。如果J21 接上JUMP,從NAND FLASH 啟動;如果J21 不接JUMP,從NOR FLASH 啟動。在這兩種啟動模式下,各晶片選擇的存儲空間分配是不同的,這兩種啟動模式的存儲分配圖如圖1 所示。圖1 左邊部分是nGCS0 晶片選擇的NOR FLASH 啟動模式下的存儲分配關系,右邊部分是NAND FLASH 啟動模式下的存儲分配關系。
一般情況下,nGCS0 晶片選擇的空間在不同的啟動模式下,映射的晶片是不一樣的。由圖1 可知,在NAND FLASH 啟動模式下,內(nèi)部的4 kB BootSRAM 被映射到nGCS0 晶片選擇的空間;在NOR FLASH 啟動模式(非NAND FLASH 啟動模式)下,與nGCS0 相連的外部記憶體NOR FLASH 就被映射到nGCS0 晶片選 擇 的 空 間[4]。SDRAM 的 位 置 空 間 范 圍 為:0x30000000 ~0x34000000。

圖1 兩種啟動模式的存儲分配圖
CPU 執(zhí)行程序所訪問的地址都是虛擬地址,而后通過MMU 將該虛擬地址轉換為真正的物理地址才能讓CPU 真正地訪問到物理地址。
S3C2440 外部存儲器的實際物理地址存儲空間被分成bank0 至bank7 共8 個bank,每個bank 的大小為128 MB,NOR FLASH 接在bank0 上,SDRAM 接在bank6 或bank7 上。
進程有4 GB 的尋址空間,其中第一部分為“用戶空間”,用來映射其整個進程空間(0x0000 0000 ~0xBFFFFFFF)即3 GB 的虛擬地址;第二部分為“系統(tǒng)空間”,用來映射(0xC0000000 -0xFFFFFFFF)1 GB 的虛擬地址??梢钥闯銮度胧较到y(tǒng)中每個進程的頁面目錄的第二部分是相同的,所以從進程的角度來看,每個進程有4 GB 的虛擬空間,較低的3 GB 是自己的用戶空間,最高的1 GB 則為與所有進程以及內(nèi)核共享的系統(tǒng)空間。
一個嵌入式系統(tǒng)從軟件的角度分析,通常劃分為4 個層次:(1)引導加載程序(包括固化在固件中的boot 代碼和BootLoader 兩大部分);(2)Linux 內(nèi)核;(3)文件系統(tǒng);(4)用戶應用程序。其中,引導加載程序是系統(tǒng)加電后運行的第一段軟件代碼。一般情況下,PC 機中的引導加載程序由BIOS (其本質(zhì)就是一段固件程序)和位于硬盤MBR 中的OS BootLoader一起組成,而在嵌入式系統(tǒng)中,通常并沒有像BIOS那樣的固件程序,因此整個系統(tǒng)的加載啟動任務就完全由BootLoader 來完成[5]。BootLoader 就是在操作系統(tǒng)內(nèi)核運行之前運行的一段程序,用于初始化硬件設備、建立內(nèi)存空間的映射表、創(chuàng)建適當?shù)南到y(tǒng)軟硬件環(huán)境,以便為最終調(diào)用系統(tǒng)內(nèi)核做準備。U-Boot 作為BootLoader 的一種,可以方便地移植到其他硬件平臺上,其源碼也值得開發(fā)者研究學習。
BootLoader 啟動程序一般由匯編代碼和C 代碼兩部分組成,U-Boot 的啟動程序也不例外,其執(zhí)行過程也分為兩個階段[6]。第一階段是匯編部分,這部分程序與硬件聯(lián)系密切,要完成的工作包括:設置中斷異常向量表、初始化看門狗等硬件設備、配置存儲器、設置堆棧等,然后跳轉到C 語言程序的入口處。第二階段即C 代碼部分,這部分的主要任務是:初始化當前所處階段所需要的外部設備、配置SDRAM 空間、調(diào)用NAND FLASH 的API 函數(shù),并將用戶程序代碼從NAND FLASH 存儲器中拷貝到SDRAM 中,最后跳轉到用戶程序的入口處[6]。啟動流程如圖2 所示。

圖2 U-Boot 啟動流程圖
從makefile 著手,定義交叉編譯器以及編譯UBoot 所需要的目標檔;然后,在開發(fā)平臺下配置Headers 檔案,為開發(fā)平臺定義設置選項或參數(shù);UBoot 啟動過程的起始程序碼start. S,其中包括設置異常變量、設置CPU 模式、設置記憶區(qū)的控制寄存器;從U-Boot 的鏈接文件U-Boot. ldr 來反向查找CPU 上電之前的第一個函數(shù)入口點,從而利用ldr 指令實現(xiàn)C 代碼位址的裝載。至此U-Boot 開始針對底層硬件進行相應的配置,主要包括:設置處理器模式;關閉開門狗;屏蔽所有中斷;清除I/D cache;關閉MMU;配置SDRAM 訪問時序;代碼自拷貝;為stage2 階段C 語言運行配置相應的段空間[7]。
調(diào)用一系列初始化函數(shù),包括指定初始化函數(shù)列表、設置可用的Flash 區(qū)、初始化記憶體分配函數(shù)、NAND Flash 初始化、LCD 初始化、系統(tǒng)初始化等之后,初始化網(wǎng)絡設備,填寫IP、MAC 地址等,最后進入U-Boot 命令行。
配置好s3c-u-boot 編譯環(huán)境和cross4.0.3 軟件交叉編譯環(huán)境,根據(jù)開發(fā)板配置,開始U-Boot 移植工作。
(1)修改Makefile。將s3c-u-boot 復制到開發(fā)用的Linux 主機進行解壓,然后在s3c-u-boot 解壓目錄下對Makefile 進行修改[8]。
ifeq(MYM(ARCH),arm)
CROSS _ COMPILE = /user/local/arm/4.0.3/bin/arm-linux-/* 指定交叉編譯器為arm-linux-* /
smdk2440_config :unconfig /* 建立2440 編譯選項格式* /
@MYM (MKCONFIG)MYM(@:_config = )arm s3c24xx smdk2440 samsung s3c2440
/* 添加新的配置選項* /
參考S3C2410 創(chuàng)建一個新目錄存放平臺相關的代碼,如下:
Board/Samsung/smdk2440/config. mk
Board/Samsung/smdk2440/ flash. c
Board/Samsung/smdk2440/ smdk2440_val. h
Board/Samsung/smdk2440/ smdk2440. c
Board/Samsung/smdk2440/lowlevel_init. S
Board/Samsung/smdk2440/u-boot. lds
include/configs/smdk2440. h
為CPU 創(chuàng)建一個新目錄s3c24xx 存放CPU 相關代碼:
Cpu/s3c24xx
(2)修改相應的程序碼。打開include/configs/smdk2440. h,先修改設置選項[9],包括:CPU 類型、開發(fā)板型號、是否使用中斷、網(wǎng)卡、malloc 池大小、內(nèi)存大小等。
#define CONFIG_ARM920T /* CPU 類型* /
#define CONFIG_S3C2440
/* 開發(fā)板類型* /
#define CONFIG_ENABLE_MMU
/* 使用MMU* /
#undef CONFIG_USE_IRQ
/* 不使用中斷* /
#def ine CFG_MALLOC_LEN (CFG_ENV_SIZE +1024* 1024)/* malloc 池大小* /
#define CFG_GBL_DATA_SIZE 128
/* 數(shù)據(jù)段大小128 B* /
#define CONFIG_DRIVER_CS8900
/* 使用CS8900 網(wǎng)卡* /
#define CS8900_BASE 0x19000300
/* CS8900A 基地址* /
#define CONFIG_SERIAL1
/* 使用串口1 * /
#define CONFIG_BAUDRATE 115200
/* 波特率* /
#define CONFIG_ETHADDR 00:40:5c:26:0a:5b
/* 網(wǎng)卡物理地址* /
#define CONFIG_NETMASK 255.255.255.0
/* 掩碼* /
#define CONFIG_IPADDR 192.168.2.20
/* 開發(fā)板IP * /
#define CONFIG_SERVERIP 192.168.2.13
/* TFTP 服務器IP * /
#define PHYS_SDRAM_1 0x30000000
/* 內(nèi)存物理地址* /
#define PHYS_SDRAM_1_SIZE 0x04000000
/* 內(nèi)存大小64 MB * /
#define CFG_LOAD_ADDR 0x30000000
/* 默認的加載地址* /
再設置NAND FLASH 的一些參數(shù),包括頁面大小、Column 地址、晶片的ID 號等[10]:
#if(CONFIG_COMMAND & CFG_CMD_NAND)
#define CFG_NAND_BASE 0x4E000000
/* Nand Flash 控制器在SFR 中暫存器的起始地址* /
#define CFG_MAX_NAND_DEVICE 1
/* 支援Nand Flash 資料* /
#define SECTORSIZE 512
/* 1 頁的大小* /
#define NAND_BLOCK_MASK(NAND_SECTOR_SIZE-1)
/* 頁遮罩* /
#define ADDR_COLUMN 1
/* 一個位元組的Clumn 地址* /
#define ADDR_PAGE 3
/* 3 位元組的頁塊地址,A9A25* /
#define ADDR_COLUMN_PAGE 4
/* 總共4 位元組的頁塊地址* /
#define NAND_ChipID_UNKNOWN 0x00
/* 位置晶片的ID 號* /
#define NAND_MAX_FLOORS 1
#define NAND_MAX_CHIPS 1
/* Nand Flash 命令底層界面函數(shù)* /
#define WRITE_NAND_ COMMAND(d,adr){rNFCMD=d;}while(0)
#define WRITE_NAND_ ADDRESS(d,adr)do{rNADDR=d;}while(0)
#define WRITE_NAND (d,adr)do{rNFDATA =d;}while(0)
#define READ_NAND (adr)(rNFDATA)
#define NAND_WAIT_READY (nand){while(!(rNFSTAT&(1 <<0)));}
#define NAND_DISABLE_CE (nand){rNFCONF|= (1 <<11);}
#define NAND_ENABLE_CE (nand){rNFCONF&= ~(1 <<11);}
最后在檔頭必須添加定義:
#define KINGFISH
加入所選用的NAND FLASH 晶片型號,在include/linux/mtd/nand_ids. h 文件中對如下結構體數(shù)值進行修改:
static struct nand_flash_dev nand_flash_ids[]={
……
{" Samsung K9F1208U08",NAND_MFR_SAMSUNG,0x76,26,0,4,0x4000,0},
……
}
再修改cpu/s3c24xx/nand. c,將int boot_nand =0修改為int boot_nand =1。另外,由于S3C2440 的時鐘主頻是400 MHz,而DMA-2440XP 提供的晶振是12 MHz[11],因此在board/Samsung/smdk2440. _val. h 中應修改為:
#define MDIV_406 92
#define PDIV_406 1
#define SDIV_406 1
修改文件cpu/s3c24xx/serial. c 中的函數(shù)void serial_setbrg (void),由于當輸入命令時,可能出現(xiàn)亂碼。這個除法實際上是整除,可能會使reg 不夠準確,因此加0.5 來彌補。
Reg=get_PCLK()/(16* gd->baudrate)-1 修改為Reg=get_PCLK()/(16* gd->baudrate+0.5)-1
(3)編譯測試。設置好后進行編譯,進入s3c-uboot 目錄進行下列操作;
#cd s3c-u-boot
#make smdk2440_config
/* 配置編譯平臺* /
#make
進行編譯,如果編譯成功,將在s3c-u-boot 目錄下生成u-boot、u-boot. bin 和u-boot. srec 3 個二進制文件。其中u-boot 是ELF 格式二進制文件,u-boot. bin是原始的二進制文件,u-boot. srec 是Motorola S-Record 格式文件。說明已經(jīng)建立好s3c2440 的U-BOOT編譯項。
在U-Boot 中,添加命令能夠為用戶提供更好的交互功能。U-Boot 版本不同,處理命令的機制也將不同。U-Boot 的每一個命令都是通過config_cmd_all. h來進行定義的。config_cmd_default. h 中定義了U-Boot啟動后自動加載命令,應該是config_cmd_default. h的子集。
一般情況下,添加U-Boot 命令分3 步進行[12]:
(1)定義添加指令。在config_cmd_all. h 中,加入一個宏定義:#define CONFIG_CMD_XXX//XXX 可以指代任何用戶自定義的添加指令
(2)實現(xiàn)添加命令的操作函數(shù)。在common/下面加入一個命令的實現(xiàn)文件cmd_XXX. c,如下所示:
#include <common. h >
#if defined((CONFIG_CMD_XXX)
在U_BOOT_CMD 結構體中添加do_XXX,然后在common 目錄的Makefile 中加入一行代碼,使實現(xiàn)文件成為編繹的目標:
COBJS-MYM(CONFIG_CMD_XXX) + = cmd_XXX. o
(3)對CONFIG_COMMANDS 進行定義 在include/configs/MYM(board). h 文件中,加入一行宏定義代碼進行定義:
#define CONFIG_CMD_XXX
按照這3 步就可以添加新的U-Boot 命令。
主要對ARM9 S3C2440 系統(tǒng)中U-Boot 移植進行了研究,可以發(fā)現(xiàn):對U-Boot 移植需要針對具體的開發(fā)板和外圍電路,因此,普遍存在局限性問題,如代碼量大、移植不夠靈活等。所以需要針對自身的開發(fā)板進行深入分析,從而在后續(xù)的嵌入式系統(tǒng)開發(fā)中靈活應用。
【1】范書瑞.ARM 處理器與C 語言開發(fā)應用[M].北京:北京航空航天大學出版社,2008.
【2】JIN Fei,ZHAO Lianyu.Development and Implementation of a Bootloader Based on the Embedded Systems[C]//3rd International Conference on Measuring Technology and Mechatronics Automation,ICMTMA 2011. Shanghai:Trans Tech Publications,2011:419 -422.
【3】張和君,張躍.基于GNU 嵌入式Bootloader 設計與開發(fā)[J].計算機工程,2006,32(15):277 -279.
【4】蘭婧,朱怡安,袁磊. 基于PXA270 嵌入式系統(tǒng)的Bootloader 研究與實現(xiàn)[J]. 計算機工程與設計,2009,30(21):4881 -4883.
【5】MA Xuewen,ZHU Mingri,CHENG Xiaohui. Design and Realization of Bootloader in Embedded System[J]. Computer Engineering,2005,31(7):96 -97.
【6】田會峰.基于S3C2440 的Bootloader 設計與實現(xiàn)[J].計算機應用,2010,29(7):29 -32.
【7】S3C2440 User's Manual [CD]. Mini2440-DVD-image,2010.
【8】長高科技有限公司. S3C2440 嵌入式設計實務[OL].www.dmatek.com.tw.
【9】張起貴,裴科.基于不同類型Flash-ROM 的Bootloader 設計[J].計算機工程與應用,2007,43(33):112 -114.
【10】李彥中,李巖.基于LPC2210 的U-Boot 移植[J]. 計算機工程與設計,2008,28(2):274 -276.
【11】S3C2440 User's Manual [CD]. Mini2440-DVD-image.2010.
【12】鄭國玲,李輝,武維.基于S3C2410 的U-Boot 的移植方法研究[J]. 計算機工程與設計,2009,30(24):643 -645.