鄧正維,鄧小武,2,鄧紹偉,2,李森林,2
(1.懷化學(xué)院 計(jì)算機(jī)科學(xué)與工程學(xué)院,湖南 懷化 418008;
2.武陵山片區(qū)生態(tài)農(nóng)業(yè)智能控制技術(shù)湖南省重點(diǎn)實(shí)驗(yàn)室,湖南 懷化 418008)
隨著計(jì)算機(jī)技術(shù)、微電子技術(shù)、現(xiàn)代制造工藝和設(shè)計(jì)能力的不斷進(jìn)步和發(fā)展,硬件的集成度越來(lái)越高,使嵌入式系統(tǒng)在生產(chǎn)、生活中被廣泛采用。但隨之而來(lái)的是用戶需求也越來(lái)越高,為了充分發(fā)揮嵌入式設(shè)備的性能,需要一個(gè)強(qiáng)大的操作系統(tǒng),而在操作系統(tǒng)運(yùn)行之前需要一段程序完成基本的初始化操作進(jìn)而啟動(dòng)操作系統(tǒng),Boot Loader就是這段程序。此舉實(shí)現(xiàn)了系統(tǒng)從硬件啟動(dòng)到操作系統(tǒng)啟動(dòng)的過(guò)渡,它固化在硬件中,被認(rèn)為是嵌入式系統(tǒng)不可缺少的一部分,其作用類(lèi)似于PC上的BIOS和GRUB。但當(dāng)前嵌入式設(shè)備上實(shí)現(xiàn)的Boot Loader大多只支持一個(gè)操作系統(tǒng)的引導(dǎo),大大限制了嵌入式設(shè)備的使用。
本文結(jié)合在ARM平臺(tái)上廣泛使用的U-Boot,詳細(xì)討論了嵌入式Boot Loader的整體架構(gòu)和運(yùn)行流程。闡述了系統(tǒng)主要硬件的原理和裸機(jī)驅(qū)動(dòng)程序設(shè)計(jì),包含系統(tǒng)時(shí)鐘設(shè)置,CPU模式設(shè)置,內(nèi)存初始化,NAND FLASH配置和操作方法,WinCE和嵌入式Linux在ARM平臺(tái)下啟動(dòng)的實(shí)現(xiàn)原理和方法。最終實(shí)現(xiàn)了在ARM平臺(tái)上的雙啟動(dòng)Boot Loader。
本文使用的開(kāi)發(fā)平臺(tái)為友善之臂Mini6410開(kāi)發(fā)板,使用Samsung公司設(shè)計(jì)生產(chǎn)的S3C6410處理器,使用2片K4X1G163PC構(gòu)成256 M SDRAM,將K9GAG08U0E作為永久存儲(chǔ)器。
S3C6410基于ARM1176JZF-S內(nèi)核[1-2],包括分立的16 kB指令和16 kB數(shù)據(jù)Cache,16 kB指令和數(shù)據(jù)TCM,及1個(gè)完全的MMU,用以處理虛擬存儲(chǔ)管理。S3C6410內(nèi)部有3個(gè)PLL,分別是APLL,MPLL和EPLL。APLL用于ARM時(shí)鐘操作,MPLL用于主時(shí)鐘操作,EPLL用于特殊用途。時(shí)鐘操作被分為三組:APLL產(chǎn)生ARM時(shí)鐘;MPLL產(chǎn)生主系統(tǒng)時(shí)鐘,用于操作AXI,AHB和APB總線;EPLL產(chǎn)生的時(shí)鐘主要用于外設(shè)IPS,對(duì)CPU的設(shè)置主要采用CPU模式、中斷和時(shí)鐘設(shè)置,Boot Loader和操作系統(tǒng)運(yùn)行在SVC模式,在U-Boot中無(wú)需中斷,時(shí)鐘的選擇根據(jù)應(yīng)用環(huán)境而定。
本系統(tǒng)選用兩片64 M×16 bit的Mobile DDR芯片,連接到S3C6410 SRAM控制器,工作頻率為133 MHz,在處理器內(nèi)部時(shí)鐘為533 MHz時(shí),能夠接近最高使用效率。內(nèi)存的初始化主要是對(duì)SRAM控制器的初始化,具體的初始化步驟在S3C6410手冊(cè)上有詳細(xì)說(shuō)明[3]。具體流程如下:
(1)使SRAM控制器進(jìn)入配置模式;
(2)填寫(xiě)內(nèi)存芯片的時(shí)序參數(shù),并開(kāi)始內(nèi)存芯片的初始化序列;
(3)配置完成后檢查狀態(tài)標(biāo)志位。
NAND FLASH作為嵌入式系統(tǒng)中廣泛使用的永久性存儲(chǔ)器[4],具有容量大、改寫(xiě)速度快等優(yōu)點(diǎn),適用于大量數(shù)據(jù)的存儲(chǔ),但是由于NAND FLASH的設(shè)計(jì)原理,在操作時(shí)有自己獨(dú)特的要求:只能以頁(yè)為單位讀寫(xiě),而且寫(xiě)時(shí)只能將1寫(xiě)為0。所以在寫(xiě)入前必須以塊為單位擦除。
S3C6410內(nèi)部包含一個(gè)NAND FLASH控制器,用戶只需配置好NAND FLASH的時(shí)序參數(shù),NAND FLASH控制器即可自動(dòng)產(chǎn)生所需時(shí)序[5]。主要配置的時(shí)序?yàn)镃LE/ALE拉高到nWE拉低的等待時(shí)間,nWE為低的持續(xù)時(shí)間,nWE拉高后CLE/ALE繼續(xù)保持為高的時(shí)間。
將NAND FLASH分為如下區(qū)域:Boot Loader,Linux_kernel,Linux_rootfs,WinCE等。通過(guò)外部跳線,NAND FLASH啟動(dòng)后,S3C6410將自動(dòng)加載前8 k內(nèi)容到S3C6410的內(nèi)部SRAM(Steppingstone)并開(kāi)始從地址0處運(yùn)行,最終加載并引導(dǎo)操作系統(tǒng),如圖1(a)所示。
引導(dǎo)操作系統(tǒng)時(shí)需要用戶在控制臺(tái)中輸入命令選擇啟動(dòng)的操作系統(tǒng),系統(tǒng)將加載制定NAND FLASH中的內(nèi)容到內(nèi)存指定位置,圖1(b)為物理內(nèi)存使用規(guī)劃,該配置內(nèi)容將保存在開(kāi)發(fā)板配置文件$(board).h中。
圖1 物理內(nèi)存和NAND FLASH劃分
U-Boot(Universal Boot Loader)是遵循 GPL協(xié)議的開(kāi)放源碼項(xiàng)目。具有系統(tǒng)引導(dǎo)、上電自檢、CRC32校驗(yàn)、設(shè)備驅(qū)動(dòng)、支持 NFS掛載、支持多種方式存儲(chǔ)等功能。在嵌入式領(lǐng)域被廣泛使用。
U-Boot屬于兩階段啟動(dòng)的Boot Loader,在第一階段由匯編語(yǔ)言完成,與處理器直接相關(guān),完成CPU模式切換,禁止看門(mén)狗,初始化內(nèi)存控制器,設(shè)置堆棧,重定位U-Boot運(yùn)行位置等操作,最后跳轉(zhuǎn)到第二階段代碼運(yùn)行。第二階段代碼主要由C語(yǔ)言完成,與目標(biāo)板相關(guān),主要完成所有設(shè)備的初始化工作,最后加載并啟動(dòng)操作系統(tǒng),具體流程如圖2所示。
圖2 U-Boot流程
U-Boot目標(biāo)文件通過(guò)<$(board)/u-boot.lds>鏈接腳本控制,該文件定義了連接到目標(biāo)文件中各段的名稱(chēng)和位置,從該文件可以看出,U-Boot由<$(CPU)/start.o>文件開(kāi)始,start.o由start.S編譯生成,包含了U-Boot第一階段的主要代碼。第二階段代碼以<$(arch)/board.c>為入口。
U-Boot支持多種平臺(tái),其驅(qū)動(dòng)程序代碼位于drivers文件夾下,各設(shè)備的板級(jí)配置信息由
為提高軟件的復(fù)用性,系統(tǒng)將操作系統(tǒng)的引導(dǎo)函數(shù)作為獨(dú)立的U-Boot命令添加到U-Boot中,支持多種命令,其命令的實(shí)現(xiàn)代碼保存在Common中,以“cmd_”作為文件前綴,添加U_Boot命令時(shí)需使用U-Boot提供的U_BOOT_CMD宏聲明。
U_BOOT_CMD各參數(shù)的意義:
(1)Name:命令的名稱(chēng),用于唯一區(qū)別命令,在U-Boot中如果命令的前綴不同,在終端可以直接輸入前綴執(zhí)行命令。
(2)Maxages:命令可以接收的最多的參數(shù)個(gè)數(shù)。
(3)Cmd:命令的實(shí)現(xiàn)函數(shù),命令被執(zhí)行時(shí),該函數(shù)被調(diào)用。
(4)Uasege:短的幫助信息,使用help時(shí)將打印該信息。
(5)Help:長(zhǎng)的幫助信息,使用help Cmd時(shí)打印該信息。
在添加完代碼后,還需在
U-Boot要啟動(dòng)操作系統(tǒng),必須首先完成必要硬件的初始化,設(shè)置好操作系統(tǒng)的運(yùn)行環(huán)境后加載并啟動(dòng)操作系統(tǒng)。
Mini6410使用三星公司設(shè)計(jì)生產(chǎn)的基于 ARM1176JZF-S內(nèi)核的S3C6410處理器[6]。為提高代碼復(fù)用度,減小移植難度,選用三星公司修改的U-Boot1.1.6版本,該版本支持與本開(kāi)發(fā)板類(lèi)似的SMDK6410,適當(dāng)修改后可以應(yīng)用在本開(kāi)發(fā)板上,可實(shí)現(xiàn)項(xiàng)目的主要功能。
修改/Makefile:添加mini6410的編譯命令:
-CROSS_COMPILE= /usr/local/arm/4.2.2-eabi/usr/bin/arm
linux-
+ CROSS_COMPILE = arm-linux-
+ mini6410_nand_conf i g : unconf i g
+@$(MKCONFIG)mini6410 arm s3c64xx mini6410 samsung
s3c6410 NAND ram256
復(fù)制參考板代碼:
board/samsung/smdk6410-> board/samsung/mini6410
include/conf i gs/smdk6410.h-> include/conf i g/mini6410.h
修改平臺(tái)相關(guān)代碼:
(1)Include/conf i gs/Mini6410.h
Mini6410.h包含了所有Mini6410開(kāi)發(fā)板的配置選項(xiàng),如SDRAM的大小、位置,NAND FLASH的大小,串口的配置,網(wǎng)卡的型號(hào),MAC地址,IP地址等信息,以及默認(rèn)的內(nèi)核啟動(dòng)參數(shù)等。
(2)CPU/s3c64xx/Start.s
Start.s是整個(gè)U-Boot的入口,包含了最基本的設(shè)置CPU模式的代碼,可調(diào)用內(nèi)存初始化函數(shù)、系統(tǒng)時(shí)鐘初始化函數(shù)、第二階段入口函數(shù)。本文件主要修改的內(nèi)容是去掉SMDK6410中包含的ONENAND初始化代碼。
(3)Board/Samsung/Mini6410/Mini6410.c
Mini6410.c包含了一些板級(jí)初始化代碼,包含網(wǎng)卡初始化函數(shù)的調(diào)用、LCD初始化函數(shù)調(diào)用代碼等,以及虛擬內(nèi)存地址到物理內(nèi)存地址的轉(zhuǎn)換函數(shù)。本文件主要修改的內(nèi)容是去掉SMDK6410中包含的CS8900網(wǎng)卡的初始化函數(shù),添加了DM9000的初始化函數(shù)和USB下載功能的支持函數(shù)。
(4)Common/Main.c
Main.c包含了U-Boot接收并執(zhí)行命令的主循環(huán)函數(shù)man_loop(),本文件的代碼與體系無(wú)關(guān),不用做其他修改。但為了提高U-Boot的可用性添加了菜單函數(shù)。
Boot Loader引導(dǎo)WinCE需要完成以下操作:
(1)設(shè)置CPU為SVC模式。
(2)完成CPU,內(nèi)存控制器,系統(tǒng)時(shí)鐘,串口,Caches,TLBs的初始化。
(3)解壓WinCE內(nèi)核鏡像文件頭,檢查校驗(yàn)和,加載內(nèi)核到指定位置。
(4)跳轉(zhuǎn)之前禁用中斷和MMU。
解壓文件頭需要分析WinCE文件頭格式[7],WinCE鏡像存在兩種格式,分別為nb0和bin。nb0是原始的二進(jìn)制鏡像,可以直接燒到FLASH/ROM中,它不包括頭,可以直接跳轉(zhuǎn)到其入口執(zhí)行,一般情況下采用nb0將內(nèi)核下載到設(shè)備的RAM中運(yùn)行。bin是一種二進(jìn)制鏡像格式,以片斷為單位組織數(shù)據(jù),每個(gè)片斷都包括一個(gè)頭,頭中指定有起始地址、長(zhǎng)度、校驗(yàn)值。Platform Builder將WinCE內(nèi)核所有文件以bin格式合并成一個(gè)文件,默認(rèn)文件名為nk.bin。Boot Loader需要將nk.bin分解成多個(gè)文件放到RAM中。
啟動(dòng)WinCE操作系統(tǒng)只需要完成必要的硬件初始化,設(shè)置好WinCE系統(tǒng)的運(yùn)行環(huán)境,然后讀取并校驗(yàn)WinCE鏡像文件,由鏡像文件頭部獲取WinCE的加載地址,并將WinCE保存到指定的位置后,跳轉(zhuǎn)到其開(kāi)始地址,就可以成功引導(dǎo)WinCE操作系統(tǒng),如圖3所示。
Boot Loader引導(dǎo)Linux內(nèi)核需要完成以下操作:(1)設(shè)置CPU為SVC模式。
(2)完成CPU,內(nèi)存控制器,系統(tǒng)時(shí)鐘,串口,Caches,TLBs的初始化。
(3)加載Linux內(nèi)核鏡像文件到內(nèi)存指定位置。
(4)設(shè)置Linux內(nèi)核啟動(dòng)參數(shù)并跳轉(zhuǎn)到內(nèi)核。
圖3 啟動(dòng)WinCE
通過(guò)Boot Loader啟動(dòng)內(nèi)核要傳遞三個(gè)參數(shù):將第一個(gè)參數(shù)放在寄存器0中,一般r0=0;第二個(gè)參數(shù)放在寄存器1中,是機(jī)器類(lèi)型ID;第三個(gè)參數(shù)放在寄存器2中,是啟動(dòng)參數(shù)標(biāo)記列表(TaggedList)在RAM中的起始基地址。
其中機(jī)器ID定義在
Linux內(nèi)核的引導(dǎo)只需要完成必要的硬件初始化操作,設(shè)置運(yùn)行環(huán)境后,讀取Linux內(nèi)核到預(yù)先規(guī)劃好的位置;設(shè)置好TaggedList后,將TaggedList,MachID,內(nèi)存參數(shù),文件系統(tǒng)位置等信息傳遞給Linux內(nèi)核后就能完成Linux內(nèi)核的引導(dǎo),如圖4所示。
本文以三星S3C6410為處理器的Mini6410開(kāi)發(fā)板為硬件平臺(tái),以U-Boot為基礎(chǔ),實(shí)現(xiàn)了在一個(gè)嵌入式設(shè)備上使用一個(gè)Boot Loader 引導(dǎo)多個(gè)操作系統(tǒng)的目的。本文將系統(tǒng)啟動(dòng)的代碼實(shí)現(xiàn)為一個(gè)獨(dú)立的函數(shù),有利于降低項(xiàng)目代碼的耦合性,方便后續(xù)嵌入式系統(tǒng)的開(kāi)發(fā)。
物聯(lián)網(wǎng)技術(shù)2018年11期